HDU 6397(容斥原理)

传送门

题面

Character Encoding

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 689    Accepted Submission(s): 262

Problem Description

In computer science, a character is a letter, a digit, a punctuation mark or some other similar symbol. Since computers can only process numbers, number codes are used to represent characters, which is known as character encoding. A character encoding system establishes a bijection between the elements of an alphabet of a certain size n and integers from 0 to n−1. Some well known character encoding systems include American Standard Code for Information Interchange (ASCII), which has an alphabet size 128, and the extended ASCII, which has an alphabet size 256.
For example, in ASCII encoding system, the word wdy is encoded as [119, 100, 121], while jsw is encoded as [106, 115, 119]. It can be noticed that both 119+100+121=340 and 106+115+119=340, thus the sum of the encoded numbers of the two words are equal. In fact, there are in all 903 such words of length 3 in an encoding system of alphabet size 128 (in this example, ASCII). The problem is as follows: given an encoding system of alphabet size n where each character is encoded as a number between 0 and n−1 inclusive, how many different words of length m are there, such that the sum of the encoded numbers of all characters is equal to k?
Since the answer may be large, you only need to output it modulo 998244353.

Input

The first line of input is a single integer T (1≤T≤400), the number of test cases.
Each test case includes a line of three integers n,m,k (1≤n,m≤105,0≤k≤105), denoting the size of the alphabet of the encoding system, the length of the word, and the required sum of the encoded numbers of all characters, respectively.

It is guaranteed that the sum of n, the sum of m and the sum of k don't exceed 5×106, respectively.

Output

For each test case, display the answer modulo 998244353 in a single line.

Sample Input

4 2 3 3 2 3 4 3 3 3 128 3 340

Sample Output

1 0 7 903

题面描述:

    给你n个大小从[0,n-1]的数字,让你在其中选取m个,使得选取的m个数的大小的和为k。

题目分析:

    这个题跟CF451E相当类似(当时没搞明白的,因此现在做题依然一(做)知(不)半(出)解(来)这次要真正的搞明白),都用到了容斥原理。

    首先,倘若题目中没有限制条件,即让我们选取m个数使得值为k的话,即题目转化成求方程组:

    中解的个数。

    按照《组合数学》中的证法,我们令,并带入式子可得:

    

    此时想象有k+m个数字‘1’排成一排,则问题等嫁祸于把这些‘1’分成m个部分,有多少种方法。

    这就相当于在k+m-1个空隙中插入m-1个隔板,根据隔板法可知,此时的方案数为

    但是题目中限制了大小只能够<n,因此在我们上诉的求法中,很显然是求多了很多方案的。因此,此时我们需要对枚举每一种不合法的条件并使用容斥原理维护整体的平衡。

    假设现在有i个数是违反了条件的(即在m个数中选i个数的方案是违反条件的),即有i个数的值是>=n的,那么显然,在此时的方程中,k是要减去i*n(去掉i个数的影响)的。故此时的方程即转化为:

    

    因此对于这种情况来说,彼时的方案数即为:

    而根据容斥原理的偶加奇减的性质,我们就可以用线性的时间求解出答案。

代码:

#include <bits/stdc++.h>
#define maxn 200005
using namespace std;
typedef long long ll;
const int mod=998244353;
ll inv[maxn],F[maxn],Finv[maxn];//分别代表逆元,阶乘,阶乘逆元
void init(){//初始化:线性求逆元,线性求阶乘,线性求阶乘逆元
    inv[1]=1;
    for(int i=2;i<=maxn;i++){
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    }
    F[0]=1;
    Finv[0]=1;
    for(int i=1;i<=maxn;i++){
        F[i]=F[i-1]*i%mod;
        Finv[i]=Finv[i-1]*inv[i]%mod;
    }
}
ll C(ll n,ll m){//组合数公式
    if(n<0||m<0||m>n) return 0;
    return F[n]*Finv[m]%mod*Finv[n-m]%mod;
}
int main()
{
    int t;
    init();
    scanf("%d",&t);
    while(t--){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        ll res=0;
        for(int i=0;i*n<=k;i++){//枚举出每一种不符合条件的个数
            if(i&1){//奇减偶加
                res=(res-C(m,i)*C(k-i*n+m-1,m-1)%mod+mod)%mod;
            }
            else{
                res=(res+C(m,i)*C(k-i*n+m-1,m-1)%mod)%mod;
            }
        }
        cout<<res<<endl;
    }
}

 

posted @ 2018-08-16 10:40  ChenJr  阅读(226)  评论(0编辑  收藏  举报