采药(jdoj1049)
题目大意:不同于NOIP的采药,这道题的描述都是一样的,只是数据范围有毒。
注释:总时间和药的种类全是100,000,每种药的时间和价值不大于10。
想法:如果想NOIP那道题一样用01背包跑的话,时间复杂度是O(10^10),显然会T掉,所以,我们想拓展一下别的方法,显然,极其容易注意到每种药物的时间和价值实在是太小了,所以在处理的过程中必定会有很多药物是一模一样的,所以,想到——多重背包。但是单纯的多重背包的时间复杂度是不发生改变的,所以我们极其容易想到一种优化——二进制优化。二进制的原理是一串2的每次加上剩余的数,是一定可以凑出所有的数的,这就是二进制优化的原理。说到这儿,这题就切了......
最后,附上丑陋的代码......
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 int a[100100]; 7 int aa[20][20]; 8 int x[100]; 9 int cnt; 10 void two(int k)//二进制优化 11 { 12 cnt=0; 13 if(k==1) 14 { 15 x[++cnt]=1; 16 return; 17 } 18 else if(k==0) 19 { 20 return; 21 } 22 else 23 { 24 k--; 25 x[++cnt]=1; 26 int now=1; 27 while(1) 28 { 29 if(k>now*2) 30 { 31 k-=now*2; 32 x[++cnt]=now*2; 33 now*=2; 34 } 35 else 36 { 37 x[++cnt]=k; 38 return; 39 } 40 } 41 } 42 } 43 int main() 44 { 45 int n,m; 46 scanf("%d%d",&n,&m); 47 int time,val; 48 for(int i=1;i<=n;i++) 49 { 50 scanf("%d%d",&time,&val); 51 aa[time][val]++; 52 } 53 for(int i=1;i<=10;i++) 54 { 55 for(int j=1;j<=10;j++) 56 { 57 memset(x,0,sizeof(x));//important ! important !! important !!! 58 two(aa[i][j]); 59 for(int ii=1;ii<=cnt;ii++) 60 { 61 for(int jj=m;jj>=i*x[ii];jj--) 62 { 63 a[jj]=max(a[jj],a[jj-i*x[ii]]+x[ii]*j); 64 } 65 } 66 } 67 } 68 int minn=-1; 69 for(int i=m;i>=1;i--) minn=max(minn,a[i]); 70 printf("%d",minn); 71 }
小结:错误
1.清数组。