解题:USACO13NOV No Change
Posted ydnhaha
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解题:USACO13NOV No Change相关的知识,希望对你有一定的参考价值。
在朴素中透着一点新意的状压DP
一个很暴力的思路是枚举位置,状态和硬币,每次二分出向前最多能买到哪里,复杂度爆炸($O(2^knklog$ $n)$)
考虑优化,不妨先预处理一下$goal[i][j]$表示每个硬币$i$在每个位置$j$最多向前能买到哪里,但是这样还是很爆炸,所以我们找来了一个不同寻常的dp状态
我们设$dp[s]$表示在$s$状态下最远能到达哪里,于是有了一个清奇的转移方程$dp[s|(1<<coin)]=max(dp[s|(1<<coin)],goal[coin][dp[s]]$,这样就可以$O(2^kk)$转移啦
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int K=17,N=100005; 6 long long val[K],goal[N][K]; 7 long long pri[N],fsum[N],dp[1<<16]; 8 long long k,n,all,ans=-1; 9 int s(int x) 10 { 11 return 1<<(x-1); 12 } 13 int main () 14 { 15 scanf("%lld%lld",&k,&n),all=(1<<k)-1; 16 for(int i=1;i<=k;i++) 17 scanf("%lld",&val[i]); 18 for(int i=1;i<=n;i++) 19 scanf("%d",&pri[i]),fsum[i]=fsum[i-1]+pri[i]; 20 for(int i=0;i<n;i++) 21 for(int j=1;j<=k;j++) 22 { 23 int l=i+1,r=n,ed=i; 24 while(l<=r) 25 { 26 int mid=(l+r)/2; 27 if(fsum[mid]-fsum[i]>val[j]) r=mid-1; 28 else l=mid+1,ed=mid; 29 } 30 goal[i][j]=ed; 31 } 32 for(int i=all;i;i--) 33 for(int j=1;j<=k;j++) 34 if(i&s(j)) dp[i^s(j)]=max(dp[i^s(j)],goal[dp[i]][j]); 35 for(int i=0;i<=all;i++) 36 if(dp[i]==n) 37 { 38 long long cnt=0; 39 for(int j=1;j<=k;j++) 40 if(i&s(j)) cnt+=val[j]; 41 ans=max(ans,cnt); 42 } 43 printf("%lld",ans); 44 return 0; 45 }
以上是关于解题:USACO13NOV No Change的主要内容,如果未能解决你的问题,请参考以下文章
洛谷P3092 [USACO13NOV]没有找零No Change
3312. [USACO13NOV]No Change状压DP
[USACO13NOV]没有找零No Change [TPLY]
洛谷 P3092 [USACO13NOV]没有找零No Change