HDU 6397 容斥

题目链接

题意:

有m个位置每个位置可以放上[0,n-1]求最终m个数总和为k的方案数

思路:

如果每个位置没有放置上限的话,那么总方案数为C(m+k-1,m-1),可以由此证明:有k+m个球放置在m个位置,每个位置至少需要有一个球,那么k+m个球就会有k+m-1个球间隙我们只需在其中选取m-1个球间隙放置隔板就可以使得每一个被隔板隔开的位置都至少有一个球,然后再从每个位置取掉一个球就是本题需要的方案

但是本题有一个限制放置个数需要在[0,n-1],那么我们就去枚举放置个数>=n的位置进行容斥,为什么要进行容斥呢,因为我们在假设全部没有>=n的时候,那只是我们的假设但是实际情况可能会有 1,2,3,...,k/n个位置有>=n,同样的道理,在我们假设只有一个位置>=n的时候,也有可能会有2,3,...,k/n个位置有>=n,这样的模型就很类似给定一个n和m个互异素数问[1,n]中有多少数不是m个互异素数中的任何一个素数的倍数

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/81772242