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 }