HDU 6397 生成函数

题目链接

题意:

m个位置每个位置可以填上[0,n-1]求m个数和为k的方案数

思路:

既然用生成函数做题的话先观察题目是否是求组合数,稍微思考发现题目求的就是组合数,于是开心的列一个生成函数(1+*x^1+x^2+...+x^n)

根据题目意思可以得到此题的指数型生成函数(1+x^1+x^2+...+x^(n-1))^m,表示每个位置可以放[0,n-1]共放置m个位置

对(1+x^1+x^2+...+x^(n-1))求和,根据等比数列求和公式得到(1-x^n)/(1-x),最终式子变成(1-x^n)^m*(1-x)^(-m)

对(1-x^n)^m二项式展开得到Σ(i=0->m)C(m,i)*(-1)^i*(x^n)^i,对(1-x)^(-m)进行泰勒展开处理得到Σ(i=0->无穷)C(m+i-1,i)x^i

泰勒展开:

因为x的最终表达式是x,所以可以得出a=1,所以f(a)==f'(a)==...==f(n)(a)==1,同时系数会因为求导和阶乘的缘故变为C(m+i-1,i),所以(1-x)^(-m)的泰勒展开结果为Σ(i=0->无穷)C(m+i-1,i)x^i

最终我们需要的是x^k前的系数就是答案了,至于怎么统计就看代码了

C++代码:

#include <bits/stdc++.h>
using namespace std;
const int mod  = 998244353;
const int maxn = 200010;

int f[maxn],inv[maxn],n,m,k;

int C( int n , int m )
{
    return 1LL*f[n]*inv[m]%mod*inv[n-m]%mod;
}

int Qpow( int a , int b )
{
    int res = 1;
    while ( b )
    {
        if ( b&1 )
            res = 1LL*res*a%mod;
        a = 1LL*a*a%mod;
        b = b>>1;
    }
    return res;
}

int main()
{
    f[0] = inv[0] = 1;
    for ( int i = 1; i<maxn ; i++ )
    {
        f[i] = 1LL*f[i-1]*i%mod;
        inv[i] = Qpow( f[i] , mod-2 );
    }
    for ( int T ; scanf ( "%d" , &T )==1 ; )
    {
        for ( int cas=1 ; cas<=T ; cas++ )
        {
            scanf ( "%d%d%d" , &n , &m , &k );
            int ans = 0;
            if ( 1LL*m*(n-1)<k )
            {
                printf ( "0\n" );
                continue;
            }
            for ( int i=0 ; i<=k/n ; i++ )
            {
                int x = 1LL*C( m , i )*C( m+k-n*i-1 , m-1 )%mod;
                if ( i%2==0 )
                    ans = ( ans+x )%mod;
                else
                    ans = ( ans-x+mod )%mod;
            }
            printf ( "%d\n" , ans );
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Game_Acm/article/details/81742608