1. 程式人生 > >「SNOI2017」英雄聯盟

「SNOI2017」英雄聯盟

題目描述

正在上大學的小皮球熱愛英雄聯盟這款遊戲,而且打的很菜,被網友們戲稱為「小學生」。 現在,小皮球終於受不了網友們的嘲諷,決定變強了,他變強的方法就是:買面板! 小皮球只會玩 NNN 個英雄,因此,他也只准備給這 NNN 個英雄買面板,並且決定,以後只玩有面板的英雄。 這 NNN 個英雄中,第 iii 個英雄有 KiK_iKi​ 款面板,價格是每款 CiC_iCi​ Q幣(同一個英雄的面板價格相同)。 為了讓自己看起來高大上一些,小皮球決定給同學們展示一下自己的面板,展示的思路是這樣的:對於有面板的每一個英雄,隨便選一個面板給同學看。 比如,小皮球共有 5 個英雄,這 5 個英雄分別有 0,0,3,2,4&0,0,3,2,4&0,0,3,2,4 款面板,那麼,小皮球就有 3×2×4=24

3×2×4=24 種展示的策略。 現在,小皮球希望自己的展示策略能夠至少達到 MMM 種,請問,小皮球至少要花多少錢呢?

共 10 組資料,第 iii 組資料滿足:N≤max⁡(5,(log⁡2i)4)N\leq\max(5,(\log_2i)^4)N≤max(5,(log2​i)4) 100%100\%100% 的資料:M≤1017,1≤Ki≤10,1≤Ci≤199M\leq 10^{17},1\leq K_i\leq 10,1\leq C_i\leq 199M≤1017,1≤Ki​≤10,1≤Ci​≤199。保證有解。

資料範圍與原題相同,但測試資料由本站會員自制,並非原資料。 時限已按照評測機速度調整,原題時限為 2000 ms。

分析:因為c,k,n的範圍很小,m的範圍很大

所以將錢數作為dp揹包的限制條件,做一次多重揹包

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
inline void FRE()
{
	freopen(".in","r",stdin);
	freopen(".out","w",stdout);
}
inline void FCL()
{
	fclose(stdin);
	fclose(stdout);
}
priority_queue<int>mp;
const int N=1e5+5;
const int mod=1e9+7;
const int inf=0x3fffffff;
inline ll read()
{
	ll s=0,f=1;
	char a=getchar();
	while(a<'0'||a>'9')
	{
		if(a=='-')
		f=-1;
		a=getchar();
	}
	while(a>='0'&&a<='9')
	{
		s=(s<<3)+(s<<1)+a-48;
		a=getchar();
	}
	return s*f;
}
inline void output(int x)
{
	int y=10,len=1;
	while(y<=x)
	{
		y*=10;
		len++;
	}
	while(len--)
	{
		y/=10;
		putchar(x/y+48);
		x%=y;
	}
}
int n,tot;
ll dp[N*20],m;
int k[N],c[N];
int main()
{
	//FRE();
	n=read();
	m=read();
	for(re i=1;i<=n;i++)
	{
		k[i]=read();
	}
	for(re i=1;i<=n;i++)
	{
		c[i]=read();
	}
	for(re i=1;i<=n;i++)
	tot+=k[i]*c[i];
	dp[0]=1;
	for(re i=1;i<=n;i++)
	{
		for(re j=tot;j>=0;j--)
		{
			for(re kk=1;kk<=k[i];kk++)
			{
				if(kk*c[i]>j)
				break;
				dp[j]=min(m,max(dp[j-kk*c[i]]*(ll)kk,dp[j]));
			}
		}
	}
	for(re i=0;i<=tot;i++)
	{
		if(dp[i]>=m)
		{
			cout<<i;
			return 0;
		}
	}
	//FCL();
	return 0;
}