「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
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_queuemp;
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<

 

你可能感兴趣的:(dp)