题目描述
You have an array of integers aa of size nn . Initially, all elements of the array are equal to 11 . You can perform the following operation: choose two integers ii ( 1 \le i \le n1≤i≤n ) and xx ( x > 0x>0 ), and then increase the value of a_iai by \left\lfloor\frac{a_i}{x}\right\rfloor⌊xai⌋ (i.e. make a_i = a_i + \left\lfloor\frac{a_i}{x}\right\rfloorai=ai+⌊xai⌋ ).
After performing all operations, you will receive c_ici coins for all such ii that a_i = b_iai=bi .
Your task is to determine the maximum number of coins that you can receive by performing no more than kk operations.
输入格式
The first line contains a single integer tt ( 1 \le t \le 1001≤t≤100 ) — the number of test cases.
The first line of each test case contains two integers nn and kk ( 1 \le n \le 10^3; 0 \le k \le 10^61≤n≤103;0≤k≤106 ) — the size of the array and the maximum number of operations, respectively.
The second line contains nn integers b_1, b_2, \dots, b_nb1,b2,…,bn ( 1 \le b_i \le 10^31≤bi≤103 ).
The third line contains nn integers c_1, c_2, \dots, c_nc1,c2,…,cn ( 1 \le c_i \le 10^61≤ci≤106 ).
The sum of nn over all test cases does not exceed 10^3103 .
输出格式
For each test case, print one integer — the maximum number of coins that you can get by performing no more than kk operations.
----------------------------------------------------------------------------------------------首先,a[i]初始时1,每次操作,x取1时可以翻倍,所以要得到1000(b[i]最大范围)总次数还是很少的,远低于k(1<=k<=1e6)一定的k,每次操作消耗一定k,获得一定价值,自然联想到背包,得到b[i]的次数需要预处理,比较省时,且比较容易进行背包。
预处理,对于每一个b[i],可以凭借小于等于它的j,推出大于它的b[i],注意j要小于等于i,j大于i时就一直停留在b[i]上止步不前。这样,每次循环,i都能推出至少比它大1的,而本次循环之后的循环又只能推出比本次更大的(不会影响到本次),所以这样推没毛病
for(int i=1; i<=1000; i++)
{
for(int j=1; j<=i; j++)
f[i+i/j]=min(f[i+i/j],f[i]+1);
}
---------------------------------------------------------------------------------------------------------------------------------
一维背包,参考背包九讲,f[b[i]]就是本次花费,w[i]是得到的奖励
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=k; j>=f[b[i]]; j--)
{
dp[j]=max(dp[j],dp[j-f[b[i]]]+w[i]);
}
}
cout<<dp[k]<<'\n';
------------------------------------------------------------------------------------------------------------------------
由于k非常大,可以在预处理的时候求一下f[i]的最大值,当n*f[i]最坏情况都《=k时,直接输出总和就行
代码如下
#include<cstdio>
#include<stack>
#include<iostream>
# include<algorithm>
# include<map>;
# include<cstring>
using namespace std;
typedef long long int ll;
int f[101000];
int b[1010];
int w[1010];
ll dp[1010000];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,k;
scanf("%d%d",&n,&k);
for(int i=1; i<=n; i++)
{
scanf("%d",&b[i]);
}
ll sum=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&w[i]);
sum+=w[i];
}
fill(f,f+1001,999999);
f[1]=0;
int mx=-1;
for(int i=1; i<=1000; i++)
{
for(int j=1; j<=i; j++)
f[i+i/j]=min(f[i+i/j],f[i]+1);
}
if(k>=mx*n)
{
cout<<sum<<'\n';
}
else
{
memset(dp,0,sizeof(dp));
for(int i=1; i<=n; i++)
{
for(int j=k; j>=f[b[i]]; j--)
{
dp[j]=max(dp[j],dp[j-f[b[i]]]+w[i]);
}
}
cout<<dp[k]<<'\n';
}
}
return 0;
}