传送门:https://codeforces.com/problemset/problem/837/D
这道题让我很惆怅......第一次打了个假贪心跑到的40多点,后面竟没破过30个点
通过这道题又让我提起了对动态规划的的三要素:状态,阶段,决策 的重视。
犯的错误有:
- 没有赋初值
- 没有判合法状态
这道题的解法:你会发现10只与最后所有选择数的2的次数和5的次数。
所以设状态 f[i][j]已经选了i个数,有j个素因数2最多拥有多少个5。
转移每次处理当前数的2的次数和5的次数,跑背包即可。(记得初值和合法判断)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> typedef long long ll; #define R register using namespace std; ll n,m; struct ddd{ ll a,b,c; }q[210]; void ch(int x){ ll v=q[x].a; while(v%2==0) q[x].b++,v/=2; while(v%5==0) q[x].c++,v/=5; return; } ll sum,f[210][6009],ans; int main (){ scanf("%lld%lld",&n,&m); memset(f,-1,sizeof(f)); for(R ll i=1;i<=n;i++) cin>>q[i].a,ch(i); f[0][0]=0; for(R ll i=1;i<=n;i++){ sum+=q[i].b; for(R ll j=min(i,m);j>=1;j--){ for(R ll k=sum;k>=q[i].b;k--){ if(f[j-1][k-q[i].b]==-1) continue; f[j][k]=max(f[j][k],f[j-1][k-q[i].b]+q[i].c); } } } for(R ll i=0;i<=sum;i++) ans=max(ans,min(i,f[m][i])); printf("%lld",ans); return 0; }