【笔记】生成函数与大背包问题
参考资料
https://blog.csdn.net/lchi1997/article/details/77860085
五边形数和分拆数模板
ll p[100005]; ll q[200005]; const ll mod = 1e9+7; void init() { int tot = 0; q[0] = 0; int cnt=0; for(int i=1;i<=100000;i++) { ll x=i; q[++cnt] =( (ll)x*(3*x-1)/2)%mod; x = -x; q[++cnt] =( (ll)x*(3*x-1)/2)%mod; } p[0]=1; for(int i=1;i<=100000;i++){ for(int now = 1,o=1;i-q[now]>=0;now++){ p[i] += o*(p[i-q[now]]); p[i] %=mod; if((now&1)==0) o=-o; } if(p[i]<0)p[i]+=mod; } }
HDU 4658
题意:
给定n,k, 将数字n划分为若干数字之和,每种数字出现次数小于k,求方案数
思路:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll p[100005]; 5 ll q[200005]; 6 const ll mod = 1e9+7; 7 void init() { 8 int tot = 0; 9 q[0] = 0; 10 int cnt=0; 11 for(int i=1;i<=100000;i++) { 12 ll x=i; 13 q[++cnt] =( (ll)x*(3*x-1)/2)%mod; 14 x = -x; 15 q[++cnt] =( (ll)x*(3*x-1)/2)%mod; 16 } 17 p[0]=1; 18 for(int i=1;i<=100000;i++){ 19 for(int now = 1,o=1;i-q[now]>=0;now++){ 20 p[i] += o*(p[i-q[now]]); 21 p[i] %=mod; 22 if((now&1)==0) o=-o; 23 } 24 if(p[i]<0)p[i]+=mod; 25 } 26 } 27 int main(){ 28 init(); 29 int _,n,k;scanf("%d",&_); 30 while(_--) { 31 scanf("%d%d",&n,&k); 32 int o=1; 33 ll ans=0; 34 for(int i=0;q[i]*k<=n;i++){ 35 ans+=o*p[n-q[i]*k]; 36 ans%=mod; 37 if((i&1)==0) o=-o; 38 } 39 if(ans<0)ans+=mod; 40 printf("%lld\n",ans); 41 } 42 }
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 ll p[100005]; 5 ll q[200005]; 6 const ll mod = 1e9+7; 7 void init() { 8 q[0] = 0; 9 int cnt=0; 10 for(int i=1;i<=100000;i++) { 11 ll x=i; 12 q[++cnt] =((ll)x*(3*x-1)/2)%mod; 13 x = -x; 14 q[++cnt] =((ll)x*(3*x-1)/2)%mod; 15 } 16 p[0]=1; 17 for(int i=1;i<=100000;i++){ 18 for(int now = 1,o=1;i-q[now]>=0;now++){ 19 p[i] += o*(p[i-q[now]]); 20 p[i] %=mod; 21 if((now&1)==0) o=-o; 22 } 23 if(p[i]<0)p[i]+=mod; 24 } 25 } 26 ll a[50005],b[100005],n,m; 27 ll f[100005]; 28 int main(){ 29 init(); 30 int ca=0; 31 while(scanf("%lld%lld",&n,&m)!=EOF){ 32 for(int i=1;i<=n;i++) scanf("%lld",&a[i]); 33 for(int i=1;i<=m;i++) scanf("%lld",&b[i]); 34 for(int i=0;i<=n;i++) f[i]=p[i]; 35 ll s=0; 36 for(int i=n+1,j=0;i<=n+n;i++,j++){ 37 s+=p[j];if(s>=mod)s-=mod; 38 f[i] = p[i] - s; 39 if(f[i]<0) f[i]+=mod; 40 } 41 for(int i=1;i<=n;i++){ 42 if(a[i]*i+i<=2*n){ 43 for(int j=n+n;j>=a[i]*i+i;j--) { 44 f[j] -= f[j-(a[i]+1)*i]; 45 while(f[j]<0)f[j]+=mod; 46 } 47 } 48 } 49 ll ans=0; 50 for(int i=1;i<=m;i++){ 51 ans+=f[n+n-b[i]]; 52 if(ans>mod)ans-=mod; 53 } 54 printf("Case #%d: %lld\n",++ca,ans); 55 56 57 } 58 59 }