[Ignatius and the Princess III] 整数的无序拆分(DP + 生成函数)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ike940067893/article/details/85265527

整数的有序拆分就是隔板法,无序拆分则有两种处理方法

DP递推

  • 我们假设 P ( n , m ) P(n,m) 是正整数 n n 无序拆分为 m m 个正整数的方案数

  • 对于某一种拆分,不妨将拆分出来的 m m 个数从小到大排序,分类讨论

    • 最小的数等于 1 1 ,那么去掉这个 1 1 ,相当于把剩下的 n 1 n-1 拆分成 m 1 m-1 个数,方案数就为 P ( n 1 , m 1 ) P(n-1,m-1)
    • 最下的数大于 1 1 ,那么将所有的数减去 1 1 ,相当于把剩下的 n m n-m 拆分成 m m 个数,方案数就为 P ( n m , m ) P(n-m,m)
  • 则最终答案为 i = 1 n P ( n , i ) \large\sum_{i=1}^nP(n,i) ,时间复杂度为 Θ ( n 2 ) \large \Theta(n^2)

  • AC code
    #include <bits/stdc++.h>
    using namespace std;
    int P[121][121];
    int main ()
    {
       for(int i = 1; i <= 120; ++i)
       {
       	P[i][1] = P[i][i] = 1;
       	for(int j = 2; j < i; ++j)
       		P[i][j] = P[i-1][j-1] + P[i-j][j];
       }
       for(int i = 1; i <= 120; ++i)
       	for(int j = 1; j <= i; ++j) //做前缀和
       		P[i][j] += P[i][j-1];
       int n;
       while(~scanf("%d", &n)) printf("%d\n", P[n][n]);
    }
    

生成函数/卷积

  • 想一想,显然可得答案为
    ( 1 + x 1 + x 2 + . . . ) ( 1 + x 2 + x 4 + . . . ) ( 1 + x 3 + x 6 + . . . ) . . . \large (1+x^1+x^2+...)\\*(1+x^2+x^4+...)\\*(1+x^3+x^6+...)\\*... 所得多项式中次数为 n n 的系数
  • 因为是多项式的乘积,就是在每个多项式中选 1 1 项,最后再加起来。在第 i i 个多项式中, 1 1 表示数 i i 不选, x k i x^{ki} 表示选了 k k i i
  • 这实际上就是把加法运算,转化为多项式的次数来做乘法/卷积。思想类似于(分治)FFT等
  • 时间复杂度为 Θ ( n 3 ) \large \Theta(n^3)
  • AC code
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    const int MAXN = 121;
    int n, ans[MAXN], tmp[MAXN];
    int main ()
    {
    	while(~scanf("%d", &n))
    	{
    		for(int i = 0; i <= n; ++i)
    			ans[i] = 1, tmp[i] = 0;
    		for(int i = 2; i <= n; ++i)
    		{
    			for(int j = 0; j <= n; j+=i)
    				for(int k = 0; k + j <= n; ++k)
    					tmp[j+k] += ans[k];
    			for(int j = 0; j <= n; ++j)
    				ans[j] = tmp[j], tmp[j] = 0;
    		}
    		printf("%d\n", ans[n]);
    	}
    }
    

猜你喜欢

转载自blog.csdn.net/Ike940067893/article/details/85265527