整数拆分:
常见问题:
<1> 有x1个1,x2个2,x3个3.....求有多少种组合相加的值小于50
<2> 有质量为 1 2 3 的砝码各n1 n2 n3枚 求称出质量为3的方案数
对于此类问题 可以抽象的构造
G(x)=(1+x^1+x^2...x^n1) * (1+x^2...x^n2/2) * (1+x^3+...x^n3/3)
//a*n^k 就是组合是k时候的方案数为a
//(1+x^2...x^n2/2) 的理解为 2 可以自身组成情况
求多项式code:
int n; cin >> n;
for (int i = 1; i <= n; i++)//n个数
a[i] = 0, b[i] = 0;
a[0] = 1;
for (int i = 1; i <= n; i++)
{
for(int j=0;j<=n;j++)
for (int k = 0; k+j <= n; k+=i)// 求当前i对方案影响 每次幂+i
{
b[k + j] += a[j];
}
for (int j = 1; j <= n; j++)
a[j] = b[j],b[j]=0;
}
cout << a[n] << '\n';
卡特兰数:
问题: 一个进栈顺序固定 1 2 3 4..... n求有多少种出栈情况
对应 01序列 进栈1 出栈0 前缀和1的个数大于0 个数
公式:C(2n,n)-C(2n,n+1)=={C(2n,n)}/(n+1)
在2n位中填入1 组合数C(2n,n)
不符合要求的:在某一个奇数位置 0的个数为m+1, 1的个数为m,此后的2(n-m)-1位上有(n-m+1)个0 ,(n-m)个1,无论接下来什么01序列,接不符合情况,所以可将此后的01互换,变成(n-m+1)个1 ,(n-m)个0。总体上便有(n+1)个0 ,(n-1)个1。所以不符合情况的就等价成为C(2n,n+1)
由于在计算过程中数字过大 有时候需要用到“质因数分解”或者“大数相乘”
禁区排列
问题:1,2,3,4四位工人,A,B,C,D四项任务,条件是:1不干B,2不干B,C,3不干C,D,4不干D,问有多少种方案?
转化成棋盘问题 ,放置棋子,行或列互不相同,设置禁区。求出禁区多项式(求出 i 颗棋子落在禁区的方案数) ci (x^i 对应的系数),运用容斥知识求出答案
禁区多项式 r(C)求法:
在图像C中任选一个格子求出在此格子放棋子和不放的方案数 相加
对于有格子不同行列的方案 相乘
容斥知识得出答案:
定义Ai 是存在 i 行棋子放入禁区事件
对于N*N的棋盘,有 N! 放置方案数,{A1∪A2∪A3......∪An}是不满足条件的所有方案数
当有 x 行棋子在禁区 其他(n-x)个棋子无条件排列 -> x*(n-x)! 方案
答案 ans = N!- c1(n-1)! + c2(n-2)!......+-cn ci即为求出的禁区多项式系数