BZOJ#Q0553. 魔法药水(potion)题解
Description
作为 G 国的国家炼金术师,你有着超高的魔法造诣。
现在在你的面前有 n 种材料,材料 i 的魔力为 a_i。
你想从这些材料中选择出一种或几种混合在一起制作一种药水。你知道不同的材料混合会给药水带来持续魔力增加效果,当你混合 k 种材料时,药水每单位时间的魔力值会增加 k。此外,材料本身的魔力值之和为药水的初始魔力值。
你在一开始(即 0 时刻)就会把所有材料混合好,在 1 时刻及以后不会再增加材料。你想知道最早能得到魔力值正好为 m 的药水的时间是多少?
Format
Input
输入第一行包含两个数字 n,m,分别表示材料数量,目标药水魔力值。
输入第二行包含 n 个整数 a_i,表示第 i 种材料的魔力值。
Output
输出共一行,表示你能获得魔力正好为 m 的药水的最早时间。
Samples
输入数据 1
3 9999999999
3 6 8
Copy
输出数据 1
4999999994
Copy
材料 1 和材料 3混合制成的药水在 0 时的魔力为 3 + 8 = 11,每秒增加 2 魔力值,因此在 4999999994 时刻的魔力为 11 + 2 * 4999999994 = 9999999999,也就是最早可能的时间。
输入数据 2
1 1000000000000000000
1
Copy
输出数据 2
999999999999999999
Copy
Limitation
对于 20% 的数据,保证 n <= 2。
对于 50% 的数据,保证 n <= 20。
对于 70% 的数据,保证 n <= 50。
对于 100% 的数据,保证 1 <= n <= 100, 1 <= a_i <= 1 * 10^7,1 * 10^9 <= m <= 1 * 10^{18}。
思路
一道DP题,直接DP即可。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,m,a[101],b[101],dmd=1e18+7,u0=1e18+7,f[106][106][106];
bool bo[106][106][106];
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
memset(f,0,sizeof(f));
memset(bo,0,sizeof(bo));
for(int j=1;j<=n;j++) b[j]=a[j]%i;
bo[0][0][0]=1;
for(int j=1;j<=n;j++){
for(int k=0;k<=min(i,j);k++){
for(int u=0;u<=i-1;u++){
if(bo[j-1][k][u]==1){
f[j][k][u]=max(f[j][k][u],f[j-1][k][u]);
f[j][k+1][(u+b[j])%i]=max(f[j][k+1][(u+b[j])%i],f[j-1][k][u]+a[j]);
bo[j][k][u]=bo[j][k+1][(u+b[j])%i]=true;
}
}
}
}
if(bo[n][i][m%i]==1) u0=min(u0,(m-f[n][i][m%i])/i);
}
cout<<u0<<endl;
return 0;
}

浙公网安备 33010602011771号