题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1190
神题。。。。。。
F[i][j]表示容量为j*2^i+W第i-1位到第0位的最大价值,
其实就是 j*2^i+W的第i-1位*2^(i-1)+W的第i-2位*2^(i-2)+......+W的第0位*2^0
注意这里j的取值为0...W>>i。
我们在读入时在b相同的宝石之间做一个背包,但是注意这时F[i][j]的容量为 j*2^i,不是j*2^i+W第i-1位到第0位。
然后我们很容易得到转移方程f[i][j]=max(f[i][j-k]+F[i-1][2*k+W的第i-1位])(0<=k<=j)
我们枚举j的时候是倒着来的,所有f[i][j-k]的容量是(j-k)*2^i。
这时候f[i][j]的容量为j*2^i+W第i-1位到第0位,f[i][j-k]的容量为(j-k)*2^i,相减得:
j*2^i+W第i-1位到第0位
-(j-k)*2^i
=2k*2^(i-1)+W的第i-1位*2^(i-1)+W的第i-2位*2^(i-2)+......+W的第0位*2^0
=(2k+W的第i-1位)*2^(i-1)+W的第i-2位*2^(i-2)+......+W的第0位*2^0
这个是F[i-1][2*k+W的第i-1位]的容量。
好神奇。
这样就成功解决了W这个上限的问题。
感觉这种方法在数位计数的问题中大有用处。
#include<cstdio> #include<cstdlib> #include<iostream> #include<fstream> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<utility> #include<set> #include<bitset> #include<vector> #include<functional> #include<deque> #include<cctype> #include<climits> #include<complex> //#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL; typedef double DB; typedef pair<int,int> PII; typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a)) #define mmcy(a,b) memcpy(a,b,sizeof(a)) #define re(i,a,b) for(i=a;i<=b;i++) #define red(i,a,b) for(i=a;i>=b;i--) #define fi first #define se second #define m_p(a,b) make_pair(a,b) #define SF scanf #define PF printf #define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;} template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;} template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-9; inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;} const DB Pi=acos(-1.0); inline int gint() { int res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } inline LL gll() { LL res=0;bool neg=0;char z; for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar()); if(z==EOF)return 0; if(z=='-'){neg=1;z=getchar();} for(;z!=EOF && isdigit(z);res=res*10+z-'0',z=getchar()); return (neg)?-res:res; } const int maxN=100; int N,W; int F[40][1010]; int main() { freopen("bzoj1190.in","r",stdin); freopen("bzoj1190.out","w",stdout); int i,j,k; while(SF("%d%d ",&N,&W),N>0) { mmst(F,0); re(i,1,N) { int a=gint(),b=0,val=gint(); while(~a&1){a>>=1;b++;} red(j,1000,a)upmax(F[b][j],F[b][j-a]+val); } re(i,0,30)re(j,0,1000)upmax(F[i][j],F[i][j-1]); for(i=1;i<=30 && (1<<i)<=W;i++) for(j=min(1000,W>>i);j>=0;j--) for(k=0;k<=j;k++) upmax(F[i][j],F[i][j-k]+F[i-1][min(k+k+((W>>i-1)&1),1000)]); PF("%d ",F[i-1][1]); } return 0; }