总会有地上的生灵,敢于直面雷霆的威光|

sLMxf

园龄:1年6个月粉丝:2关注:0

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;
}

本文作者:sLMxf

本文链接:https://www.cnblogs.com/SLMXF/p/18564570

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   sLMxf  阅读(3)  评论(0编辑  收藏  举报  
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示