Make them Equal tj

题目传送门/题目传送门

简述题意

你有一个长度为 nn 的数列 ai=1a_i=1,和两个长度为 nn 的序列 b,cb,c
定义一次操作为:确定 x,ix,i,使得 aiai+aixa_i←a_i+\lfloor \dfrac{a_i}{x}\rfloor
如果 ai=bia_i=b_i,贡献加 cic_i。求最大贡献。

算法分析

DP。

先算出1到每个值进行操作的最小次数,记做 f(n)f(n)

接着,对于每一问,将它的价值记做 cic_i,需要用钱 f(bi)f(b_i)

0101 背包便可。

代码实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
int f[20000];
int w[10005],v[10005],dp[100005];
int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
signed main()
{
	int T=read();
	memset(f,127,sizeof(f));
	f[1]=0;
	for(int i=1;i<=1000;i++)
	{
		for(int j=1;j<=i;j++)
			f[i+i/j]=min(f[i]+1,f[i+i/j]);//提前计算f(n)
	}
	while(T--)
	{
		int n=read(),k=read(),sum1=0,sum2=0;
		for(int i=1;i<=n;i++)
		{
			int x=read();
			w[i]=f[x];sum1+=f[x];
		}
		for(int i=1;i<=n;i++) v[i]=read(),sum2+=v[i];
		if(sum1<=k)//不加上这个,离奇RE
		{
			cout<<sum2<<endl;
			continue;
		}
		int ans=0;
		memset(dp,0,sizeof(dp));
		dp[0]=0;
		for(int i=1;i<=n;i++)
			for(int j=k;j>=w[i];j--)
				dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		for(int i=0;i<=k;i++) ans=max(ans,dp[i]);
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2023-12-23 11:49  sLMxf  阅读(15)  评论(0)    收藏  举报  来源