bzoj 3312 No Change
题目大意:
到商场购物,他的钱包里有K个硬币
想按顺序买 N个物品,第i个物品需要花费c(i)块钱
在依次进行的购买N个物品的过程中,可以随时停下来付款,每次付款只用一个硬币
支付购买的内容是从上一次支付后开始到现在的这些所有物品(前提是该硬币足以支付这些物品的费用)
如果支付的硬币面值大于所需的费用,他不会得到任何找零
请计算出在购买完N个物品后,最多剩下多少钱
思路:
状压dp
设使用了状态为i的硬币最远能够达到哪个物品
转移的时候从 i 里扔掉每一个1来转移过来
最后看一眼哪些dp可以达到n 取一下状态的补集求一下和
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstdlib> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #define inf 2139062143 10 #define ll long long 11 #define MAXN 100100 12 using namespace std; 13 inline int read() 14 { 15 int x=0,f=1;char ch=getchar(); 16 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 17 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 18 return x*f; 19 } 20 int k,n,dp[1<<17],s[MAXN],ans,val[18]; 21 int lowbit(ll x) {return x&(-x);} 22 int main() 23 { 24 k=read(),n=read();int x,t; 25 for(int i=1;i<=k;i++) val[i]=read(); 26 for(int i=1;i<=n;i++) s[i]=s[i-1]+read(); 27 for(int i=0;i<k;i++) dp[1<<i]=upper_bound(s+1,s+n+1,val[i+1])-s-1; 28 for(int i=1;i<(1<<k);i++) 29 { 30 if(i==lowbit(i)) continue; 31 for(int t=i,r=i;r;r-=lowbit(r)) 32 { 33 t-=lowbit(r); 34 dp[i]=max(dp[i],(int)(upper_bound(s+dp[t]+1,s+n+1,s[dp[t]]+val[int(log2(lowbit(r)))+1])-s-1)); 35 t+=lowbit(r); 36 } 37 } 38 ans=-1; 39 for(int i=1;i<(1<<k);i++) 40 { 41 if(dp[i]!=n) continue;t=0; 42 for(int j=((1<<k)-1)^i;j;j-=lowbit(j)) 43 t+=val[int(log2(lowbit(j)))+1]; 44 ans=max(t,ans); 45 } 46 printf("%d",ans); 47 }