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 }
View Code
posted @ 2018-03-20 19:40  jack_yyc  阅读(97)  评论(0编辑  收藏  举报