牛客网暑期ACM多校训练营(第六场) C(Generation I)

题目描述 
Oak is given N empty and non-repeatable sets which are numbered from 1 to N.

Now Oak is going to do N operations. In the i-th operation, he will insert an integer x between 1 and M to every set indexed between i and N.

Oak wonders how many different results he can make after the N operations. Two results are different if and only if there exists a set in one result different from the set with the same index in another result.

Please help Oak calculate the answer. As the answer can be extremely large, output it modulo 998244353.
输入描述:
The input starts with one line containing exactly one integer T which is the number of test cases. (1 ≤ T ≤ 20)

Each test case contains one line with two integers N and M indicating the number of sets and the range of integers. (1 ≤ N ≤ 1018, 1 ≤ M ≤ 1018, )
输出描述:
For each test case, output "Case #x: y" in one line (without quotes), where x is the test case number (starting from 1) and y is the number of different results modulo 998244353.

输入

2
2 2
3 4
输出

Case #1: 4
Case #2: 52

题意:现在有N个空的集合(集合是普通定义上的集合),现在有N次操作,每一次操作可以把在[1,M]中选一个数X放入到[i,N]的集合中(注意是[i,N]全部集合),现在问N次操作之后这些集合组成的集合不同的的个数有多少个。

思路:

      首先我们知道选同一种颜色取两次及两次以上去填充N个箱子后面那个是不管用的,那么我们就可以设从M个颜色中选了k个去放入N个箱子内,后面枚举k从1到min(N,M)去算,那么选好了k种颜色填充N个箱子,由于还要保证第一个箱子必须有颜色,那么有k种选择,剩下k-1种颜色去填充n-1个位置,就是C(n-1,k-1)种选择,由于k-1种颜色放的顺序还要有(k-1)!种,那么最后得答案就是sigma(k=1->min(n,m))C(m,k)*k*C(n-1,k-1)*(k-1)!。这道题n和m有一种可能大于1e6,所以将公式整合一下,我们容易知当k=1的时候的值,然后递推着求后面min(n,m)个值。

注意所有数的取模!!!!wa了好多发QAQ

代码:

#include <set>
#include <map>
#include <deque>
#include <stack>
#include <queue>
#include <cmath>
#include <time.h>
#include <vector>
#include <string>
#include <math.h>
#include <bitset>
#include <cstring>
#include <cstdlib>
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
#define ll long long
#define inf 0x3f3f3f3f
#define ull unsigned long long
using namespace std;
  
const ll mod=998244353;
ll inv[1000005];
ll a[1000005];
long long pow_mod(long long a,long long b)
{
    a=a%mod;
    long long ans=1;
    while(b)
    {
        if(b&1)
        {
            ans=(ans*a)%mod;
            b--;
        }
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
void init()
{
    for(int i=1;i<=1000000;i++)
    {
        inv[i]=pow_mod(i,mod-2);
    }
}
int main()
{
    init();
    int T;
    int Case=0;
    scanf("%d",&T);
    while(T--)
    {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        cout<<"Case #"<<++Case<<": ";
        if(n==1)
        {
            cout<<m%mod<<endl;
            continue;
        }
        if(m==1)
        {
            cout<<1<<endl;
            continue;
        }
        ll k=min(n,m);
        ll ans=0;
        a[1]=m%mod;
        ans+=a[1];
        for(int i=2;i<=k;i++)
        {
            ll e=(m-i+1)%mod;
            ll r=(n-i+1)%mod;
            ll q=e*r%mod;
            a[i]=(((a[i-1]*q%mod)*inv[i-1])%mod)%mod;
            ans=(a[i]+ans)%mod;
        }
        cout<<ans%mod<<endl;
    }
}
/*
  
2
2 2
3 4
  
*/

猜你喜欢

转载自blog.csdn.net/snayf/article/details/81435039