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\) 得最大。和状态不冲突。
但是我们发现两个条件很难同时满足:
- \(sum\) 最大
- \(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;
}

浙公网安备 33010602011771号