生成函数(母函数)
母函数又称生成函数。定义是给出序列:a0,a1,a2,...ak,...an,
那么函数G(x)=a0+a1*x+a2*x2+....+ak*xk +...+an* xn 称为序列a0,a1,a2,.......ak,......的母函数(即生成函数)。
1. 问题 n=x1+x2+x3+...+xk有多少个非负整数解?这道题是学排列与组合的经典例题了。
把每组解的每个数都加1,就变成n+k=x1+x2+x3+...+xk的正整数解的个数了。
教材上或许会出现这么一个难听的名字叫“隔板法”:把n+k个东西排成一排,在n+k-1个空格中插入k-1个“隔板”。
答案我们总是知道的,就是C(n+k-1,k-1)。它就等于C(n+k-1,n)。
它关于n的生成函数是g(x)=1/(1-x)^k。
2. 这个公式非常有用,是把一个生成函数还原为数列的武器。而且还是核武器。1/(1-x)^n=1+C(n,1)x^1+C(n+1,2)x^2+C(n+2,3)x^3+...+C(n+k-1,k)x^k+...。
找单词
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9784 Accepted Submission(s): 6805
然后包括N行数据,每行包括26个<=20的整数x1,x2,.....x26.
#include <bits/stdc++.h> #define mp make_pair #define pb push_back #define fi first #define se second #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define huan printf("\n"); #define debug(a,b) cout<<a<<" "<<b<<" "<<endl; using namespace std; const int maxn= 1e2+10; const int inf = 0x3f3f3f3f; typedef long long ll; ll a[maxn],b[maxn]; int main() { int t; cin>>t; while(t--) { fillchar(a,0); fillchar(b,0); a[0]=1; for(int i=1;i<=26;i++) { int x; cin>>x; for(int j=0;j<=50;j++) { for(int k=0;k<=x&&(j+i*k<=50);k++) { b[j+k*i]+=a[j]; } } for(int j=0;j<=50;j++) { a[j]=b[j]; b[j]=0; } } ll ans=0; for(int i=1;i<=50;i++) { ans+=a[i]; } cout<<ans<<endl; } }
Ignatius and the Princess III
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 25750 Accepted Submission(s): 17803
"The second problem is, given an positive integer N, we define an equation like this:
N=a[1]+a[2]+a[3]+...+a[m];
a[i]>0,1<=m<=N;
My question is how many different equations you can find for a given N.
For example, assume N is 4, we can find:
4 = 4;
4 = 3 + 1;
4 = 2 + 2;
4 = 2 + 1 + 1;
4 = 1 + 1 + 1 + 1;
so the result is 5 when N is 4. Note that "4 = 3 + 1" and "4 = 1 + 3" is the same in this problem. Now, you do it!"
递推法
![](https://gss3.bdstatic.com/-Po3dSag_xI4khGkpoWK1HF6hhy/baike/s%3D9/sign=0e00a53e43540923ae696f4f92502a/aec379310a55b3196875d96849a98226cffc171a.jpg)
![](https://gss0.bdstatic.com/94o3dSag_xI4khGkpoWK1HF6hhy/baike/s%3D13/sign=7eea3f4bda160924d825a618d4074c76/08f790529822720ec4e4bae771cb0a46f21fab81.jpg)
#include <bits/stdc++.h> #define mp make_pair #define pb push_back #define fi first #define se second #define all(a) (a).begin(), (a).end() #define fillchar(a, x) memset(a, x, sizeof(a)) #define huan printf("\n"); #define debug(a,b) cout<<a<<" "<<b<<" "<<endl; using namespace std; const int maxn= 1e2+50; const int inf = 0x3f3f3f3f; typedef long long ll; ll a[maxn],b[maxn]; int main() { int n; while(cin>>n) { fillchar(a,0); fillchar(b,0); a[0]=1; for(int i=1;i<=n;i++) //枚举第i个多项式 每一项的系数都为1 { for(int j=0;j<=n;j++) //保留x0----xn项 { for(int k=0;j+i*k<=n;k++) //枚举第i个多项式的每一项 { b[j+k*i]+=a[j]; //b数组保存中间值 } } for(int j=0;j<=n;j++) { a[j]=b[j]; //b数组传值给a b[j]=0; } } cout<<a[n]<<endl; } } /*----------------------------------------------------------------------------------------*/ #include<bits/stdc++.h> #define ll long long using namespace std; //记忆化递归法求解整数划分 ll ans[300][300]; ll GetPartitionCount(int n, int m) { if(ans[n][m]>0) return ans[n][m]; if (n == 1 || m == 1)return ans[n][m]=1; if (n < m)return ans[n][m]=(GetPartitionCount(n, n)); if (n == m)return ans[n][m]=(1 + GetPartitionCount(n, n - 1)); else return ans[n][m]=(GetPartitionCount(n - m, m) + GetPartitionCount(n, m - 1)); } int main() { int n,m; ll sum; while (scanf("%d",&n)==1) { memset(ans,0,sizeof(ans)); m=n; sum = GetPartitionCount(n, m); printf("%lld\n", sum); } return 0; }