hdu1028
作者:互联网
题目链接
题目概述
求一个整数\(N\)的可重无序拆分.
解题思路
稍加变换,原问题等价于方程:
\[1e_1+2e_2+3e_3+\cdots +ne_n=n,\,(e_i \ge 0, i= 1, 2, 3,\dots) \]
解的个数,可以看做是将\(n\)个相同的小球放到\(n\)个相同的盒子允许空盒的数目.对应的结果就是函数:
\[g(x) = (1+x+x^2+x^3+\cdots)(1+x^2+x^4+\cdots)\cdots(1+x^n+x^{2n}+\cdots) \]
展开式中\(x^n\)项的系数.对于\(1,x^i,x^{2i},\dots\)可以理解为使用整数\(i,0,1,2,\dots\)次,得到整数\(1,i,2i,\dots.\)所以展开式中的\(x^n\)就是\(x^{1e_1},x^{2e_2},\dots\)相乘,使得\(x\)的指数部分之和是\(n.\)
注意
因为这里每一个整数\(i\)使用的数量都没有限制,所以写的是\(1,x^i,x^{2i},\dots\),假设整数\(i\)使用的次数只能是奇数,那么整数\(i\)的展开应该是\((x^i+x^{3i}+\dots)\);或者整数\(i\)的使用次数只能是序列\(\{b_1,b_2,\dots\}\)中的,那么\(i\)的展开应该是\((x^{ib_1}+x^{ib_2}+\dots).\)
另外注意上面方程前面那个\(e_i\)前面的的系数\(i\),\(e_i\)表示的是使用这个系数多少次,而这个系数表示另外一种约束,可以这样理解,就是使用一个东西必须要使用\(i\)次,如果上面的方程变为:
\[e_1+e_2+e_3+\cdots +e_n=n,\,(e_i \ge 0, i= 1, 2, 3,\dots) \]
那么对应的母函数就是:
\[g(x) = (1+x+x^2+x^3+\cdots)(1+x^1+x^2+\cdots)\cdots(1+x^2+x^{2}+\cdots) = (1+x+x^2+x^3+\cdots)^n. \]
代码实现
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200;
ll buf[N];
ll temp[N];
void calculate(){
fill(buf, buf + N, 1);
fill(temp, temp + N, 0);
for (int k = 2; k < N; ++k){
for (int i = 0; i < N; ++i){
for(int j = 0; i+j < N; j +=k ){
// temp是当前的k的展开式与上一轮计算的结果.
temp[i + j] += buf[i];
}
}
// 更新这一轮的结果.
memcpy(buf, temp, sizeof(ll)*N);
fill(temp, temp + N, 0);
}
}
int main(int argc, const char** argv) {
calculate();
int n;
while (~scanf("%d",&n)){
printf("%lld\n", buf[n]);
}
return 0;
}
下面通过这个表格给出计算\((1+x^1+x^2+x^3+x^4)(1+x^2+x^4)\)的计算过程:
(表格A(上一轮计算的结果))
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
(表格B(这一轮计算的结果))
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 1 | 1 | 1 | |||||
1 | 1 | 1 | 1 | 1 | |||||
1 | 1 | 1 | 1 | ||||||
1 | 1 | 1 | 1 | ||||||
1 | 1 | 1 | |||||||
1 | 1 | 1 | |||||||
1 | 1 | ||||||||
1 | 1 | ||||||||
1 | |||||||||
1 |
(整理之后是这一轮计算的值(对应程序中的temp))
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 |
(更新这一轮计算的结果准备计算下一轮(对应程序中的buf))
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|
1 | 1 | 2 | 2 | 3 | 3 | 4 | 4 | 5 | 5 |
按照上面表格所示的那样,先计算相邻的两项系数作为当前一轮的计算结果,然后在下一轮中座椅一项与下一项进行计算得到下一轮就散的记过,然后更新,这样滚动更新计算,最后的buf
中的系数就是整数拆分的结果(这里为了便于识别,没有将表格中空白的0
显示的标出).
其它
标签:dots,temp,int,一轮,cdots,buf,hdu1028 来源: https://www.cnblogs.com/2018slgys/p/13304900.html