Connecting...

AT_abc192_f [ABC192F] Potion

AT_abc192_f [ABC192F] Potion - 洛谷

观察得:

\(sum +kt=X\)

其中 \(sum,k,t,X\) 分别指:选了 \(k\) 个数的和,选了 \(k\) 个数,需要 \(t\) 天,题目所给。

我们设计状态,\(dp_{i,j}\) 表示前 \(i\) 个数选了 \(j\) 个数的最小天数。

观察得:我们知道天数 \(t\) 和几个数 \(k\) 就知道 \(sum\)

\(t=\frac{X-sum}{k}\)

观察:当几个数 \(k\) 一定,合法的 \(sum\) 得最大。和状态不冲突。

但是我们发现两个条件很难同时满足:

  1. \(sum\) 最大
  2. \(sum\) 合法。即 \(t\) 为整数。

和状态有所冲突,我们需要添加状态,和同余有关。

设计 \(dp_{i,j,k}\) 表示:前 \(i\) 个数选了 \(j\) 个数,\(sum \bmod j= k\) 的最大 \(sum\)

发现 \(k\) 这里要标定同一个除数。否则会出现这种不知对错的东西:

\[dp_{i,j,k}=\max dp_{i-1,j-1,(k-a_i)\bmod (j-1)}+a_i\\ \]

我们枚举预计选 \(s\) 个。然后进行转移:

\[dp_{i,j,k}=\max dp_{i-1,j-1,(k-a_i)\bmod s}+a_i\\ \]

注意:

多组 \(s\) 清空。变量范围别加太多以致转移不起来。

Code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=111;
int n,x,a[N];
int dp[N][N][N]/*dp[i][j][k]前i个拿了j个模s为k的最大sum*/;
signed main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>x;
	int ans=1e18,sm=0;
	for(int i=1;i<=n;++i)cin>>a[i];
	for(int s=1;s<=n;++s){
		for(int i =1;i<=n;++i)for(int j=0;j<=n;++j)for(int k=0;k<=n;++k) dp[i][j][k]=0;
		for(int i=1;i<=n;++i){
			dp[i][1][a[i]%s]=a[i];
			for(int p=1;p<=i;++p)  dp[i][1][a[i]%s]=max(dp[p][1][a[i]%s],dp[i][1][a[i]%s]);
			for(int j=1;j<=s;++j){
				for(int k=0;k<s;++k){
					dp[i][j][k]=max(dp[i][j][k],dp[i-1][j][k]);//不拿
					if(dp[i-1][j-1][((k-a[i])%s+s)%s])
						dp[i][j][k]=max(dp[i][j][k],dp[i-1][j-1][((k-a[i])%s+s)%s]+a[i]); //拿
//					cerr<<s<<" "<<i<<" "<<j<<" "<<k<<" "<<dp[i][j][k]<<"\n";
				}
				if(dp[n][s][x%s]&&s==j)ans=min(ans,(x-dp[n][s][x%s])/s);
			}
		}
	}
	cout<<ans;
	return 0;
}
posted @ 2025-07-27 21:39  余亦宸  阅读(9)  评论(0)    收藏  举报