牛客网暑期ACM多校训练营(第六场) C. Generation I(组合数学)

链接:https://www.nowcoder.com/acm/contest/144/C
来源:牛客网

题目描述
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 10 18 , 1 M 10 18 ,这里写图片描述 )
输出描述:
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.
示例1
输入

复制
2
2 2
3 4
输出

复制
Case #1: 4
Case #2: 52

题意

你对n个集合进行n次操作,第i次操作都从第i个集合开始,每次操作可以向从i到n的集合中插入一个元素,元素范围为 1 m ,n个集合为一个大集合,问你有多少个不同的大集合

思路

我们以 n = 4 , m = 4 为例,先举一个 4 , 4 的两个集合

1 { 1 } 1 1 { 1 } 1 1 2 { 1 , 2 } 1 1 2 3 { 1 , 2 , 3 }

1 { 1 } 1 1 { 1 } 1 1 3 { 1 , 3 } 1 1 3 2 { 1 , 3 , 2 }

我们现在只看第n层,两个不同的集合的最后一层的元素都含有 1 , 2 , 3 ,但是这两个集合是不同的两个集合,原因是数字出现的顺序会影响上一层的集合,所以最后一层元素的顺序是影响总的个数的,那么我们假设第n层由k个元素,方案数就是相当于从m个数中选k个数的排列数,即 A m k ,选定好这k个数后,答案还不是 A m k ,因为由于他可以插重复的元素,而重复的元素只与其他第一次出现有关,例如
1 { 1 } 1 2 { 1 , 2 } 1 2 1 { 1 , 2 } 1 2 1 3 { 1 , 2 , 3 }

1 { 1 } 1 1 { 1 , 1 } 1 1 2 { 1 , 2 } 1 1 2 3 { 1 , 2 , 3 }

这里是两个不同的集合,而不同的原因是来自于, 2 出现的位置,由于第一个元素是固定的如
1 , 1 , 1 , 2 , 1 , 2 { 1 , 2 } 1 , 1 , 2 , 1 , 1 , 2 { 1 , 2 } ,第一个出现的数会把第二个出现的数的前面都填满,而第二个出现的数才对答案有贡献,所以就相当于在n-1个位置上填k-1个数即 C n 1 k 1 ,那么答案就应该是 A m k C n 1 k 1 ,如何k从1枚举到 m i n ( n , m ) ,即
k = 1 m i n ( n , m ) A m k C n 1 k 1

n和m都比较大,但两者肯定有一个较小,所以最多只用算 1 e 6 个数组合和排列数最多也只有算 ( n 1 ) ( n 2 ) ( n 3 ) ( n 1 e 6 ) 1 2 3 1 e 6 m ( m 1 ) ( m 2 ) ( m 3 ) ( m 1 e 6 ) ,所以多处理一个逆元就可以了

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
const long long mod=998244353;
const int N=1e6+5;
long long inv[N];
int main()
{
    inv[0]=inv[1]=1;
    for(int i=2; i<N; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    int t,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        long long n,m;
        scanf("%lld%lld",&n,&m);
        long long ans=m%mod,sum=m%mod;
        long long m_=m%mod,n_=n%mod;
        for(int i=1; i<min(n,m); i++)
        {
            sum=sum*(m_-i)%mod*(n_-i)%mod*inv[i]%mod;
            ans=(ans+sum)%mod;
        }
        printf("Case #%d: %lld\n",cas++,(ans+mod)%mod);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ftx456789/article/details/81430707
今日推荐