题目:传送门
题意:给一个初始全为1的a序列,有k次修改,每次选一个位置i和一个整数x,让
a
i
a_{i}
ai+
a
i
a_{i}
ai/x,当
a
i
a_{i}
ai=
b
i
b_{i}
bi,获得
c
i
c_{i}
ci,问最多修改k次,最多获得多少分?
分析:除了k,其余数据也不是很大,可以先初始化一下1-1000以内的数的最少操作数。虽然k很大,但是其实对于一个数最多操作次数不超过12次,那么最多只需要操作12000次可以使所有对应位置相等。那么接下来动态规划一下就行了。
状态转移方程:
dp[j]=max(dp[j],dp[j-b[i]]+c[i]);
/*
dp[i]记录次数为i是最大的分数
b[i]表示最少操作数
c[i]表示分数
*/
代码:
#include<iostream>
#include<iostream>
#define IOS ios::sync_with_stdio(false);
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
using namespace std;
typedef long long ll;
typedef double dd;
typedef pair<int, int> PII;
const int N=1e5+10;
int dx[4]={-1,0,0,1};
int dy[4]={0,1,-1,0};
int lowbit(int x){
return x&-x;
}
int f[N];
void init(){
int n=1e3+10;
memset(f,0x3f,sizeof f);
f[1]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i+i/j]=min(f[i+i/j],f[i]+1);
}
}
}
ll dp[N]{};
int T;
int n,m;
int b[N],c[N];
int main(){
cin>>T;
init();
while(T--){
cin>>n>>m;
m=min(12*n,m);
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++){
int x;
cin>>x;
b[i]=f[x];
}
for(int i=1;i<=n;i++) cin>>c[i];
for(int i=1;i<=n;i++){
for(int j=m;j>=b[i];j--){
dp[j]=max(dp[j],dp[j-b[i]]+c[i]);
}
}
cout<<dp[m]<<"\n";
}
return 0;
}