BZOJ3312: [Usaco2013 Nov]No Change

n<=1e5个东西,从左往右买,有K<=16个钱,每次花一个钱买可以买多个,买完不找零,问所有买完最多剩多少钱,无解-1.

一开始以为物品要做状态一直想不出来。。。。

f(i)--钱的状态为i最多能买多少个东西,f(i)=从f(j)+1开始买能买到哪里,其中j是i某一位少一个1的状态。最多买多少,在前缀和上二分。

dp时老是考虑多状态,咋整啊?看看哪些去掉对决策是没有影响的。不要老是受套路的影响一定要搞个“前i个数字”之类的状态,有时候是没有用的。

 1 #include<cstring>
 2 #include<cstdlib>
 3 #include<cstdio>
 4 //#include<assert.h>
 5 //#include<time.h>
 6 #include<math.h>
 7 #include<algorithm>
 8 //#include<iostream>
 9 using namespace std;
10 
11 bool isdigit(char c) {return c>='0' && c<='9';}
12 int qread()
13 {
14     char c;int s=0,f=1;while (!isdigit(c=getchar())) f=(c=='-'?-1:1);
15     do s=s*10+c-'0'; while (isdigit(c=getchar())); return s*f;
16 }
17 
18 int n,K;
19 #define maxn 100011
20 int f[maxn],sum[maxn],v[20];
21 int how(int x,int base)
22 {
23     int L=x,R=n;
24     while (L<R)
25     {
26         const int mid=(L+R+1)>>1;
27         if (base+sum[x]>=sum[mid]) L=mid;
28         else R=mid-1;
29     }
30     return L;
31 }
32 int main()
33 {
34     K=qread(),n=qread();
35     for (int i=1;i<=K;i++) v[i]=qread();
36     sum[0]=0;for (int i=1;i<=n;i++) sum[i]=sum[i-1]+qread();
37     f[0]=0;int ans=-1;
38     for (int i=1;i<(1<<K);i++)
39     {
40         int left=0;f[i]=0;
41         for (int j=1;j<=K;j++)
42             if (i&(1<<(j-1)))
43             {
44                 int k=i^(1<<(j-1));
45                 f[i]=max(f[i],how(f[k],v[j]));
46             }
47             else left+=v[j];
48         if (f[i]>=n) ans=max(ans,left);
49     }
50     if (ans>=0) printf("%d\n",ans);
51     else puts("-1");
52     return 0;
53 }
View Code

 

posted @ 2017-10-26 15:51  Blue233333  阅读(176)  评论(0编辑  收藏  举报