bzoj 1042: [HAOI2008]硬币购物
2016-06-20
完全背包DP(做的时候都忘记自己当初怎么学得了 囧。。),题目非同寻常的地方是n很小,价值固定,但有多组测试数据,我们首先想到将之按完全背包预处理出来,每一组时再减去不合法的,
减去不合法的可以用容斥原理,第一个不合法的方案数就是让第一个先取d1+1个其余随便取 f[s-(d1+1)*c1],那就减去1,2,3,4加上12,13,14,23,24,34减去123,124,134,234加上1234。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<queue> 7 #define M 100008 8 #define ll long long 9 #define Mo 12345678 10 using namespace std; 11 ll read() 12 { 13 char ch=getchar(); 14 ll x=0,f=1; 15 for(;ch<'0'||ch>'9';ch=getchar()) 16 if(ch=='-') 17 f=-1; 18 for(;ch>='0'&&ch<='9';ch=getchar()) 19 x=x*10+ch-'0'; 20 return x*f; 21 } 22 int c[5],n,m,a[5],b[5]; 23 ll f[M]; 24 int main() 25 { 26 f[0]=1; 27 for(int i=1;i<=4;i++) 28 c[i]=read(); 29 n=read(); 30 for(int i=1;i<=4;i++) 31 for(int j=c[i];j<=100000;j++) 32 f[j]+=f[j-c[i]]; 33 for(int i=1;i<=n;i++) 34 { 35 for(int j=1;j<=4;j++) 36 a[j]=read(); 37 m=read(); 38 ll an=f[m]; 39 for(int j=1;j<=4;j++) 40 if(m-(a[j]+1)*c[j]>=0) 41 an-=f[m-(a[j]+1)*c[j]]; 42 for(int j=1;j<=4;j++) 43 for(int k=j+1;k<=4;k++) 44 if(m-(a[j]+1)*c[j]-(a[k]+1)*c[k]>=0) 45 an+=f[m-(a[j]+1)*c[j]-(a[k]+1)*c[k]]; 46 for(int j=1;j<=4;j++) 47 for(int k=j+1;k<=4;k++) 48 for(int l=k+1;l<=4;l++) 49 if(m-(a[l]+1)*c[l]-(a[j]+1)*c[j]-(a[k]+1)*c[k]>=0) 50 an-=f[m-(a[l]+1)*c[l]-(a[j]+1)*c[j]-(a[k]+1)*c[k]]; 51 if(m-(a[1]+1)*c[1]-(a[2]+1)*c[2]-(a[3]+1)*c[3]-(a[4]+1)*c[4]>=0) 52 an+=f[m-(a[1]+1)*c[1]-(a[2]+1)*c[2]-(a[3]+1)*c[3]-(a[4]+1)*c[4]]; 53 printf("%lld\n",an); 54 } 55 return 0; 56 }