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

posted @ 2025-10-24 20:32  bz02_2023f2  阅读(6)  评论(0)    收藏  举报  来源