牛客多校第六场 C Generation I (简单排列组合)

输入:

2
2 2
3 4

输出:

Case #1: 4
Case #2: 52

题意:有 n个不重复集合 也就是set 标号为1~n  现有m个数   现有n个操作  第i次操作可以从 1到m中 选一个数 插入到 i~n的所有集合   问  n次操作后 有多少种不同的情况   (两种不同的情况 为 存在 同一标号的 两个set不同 )

题解:因为填一次数字 是把第i位之后的所有集合都填一遍  那么我们可以只考虑第i步时放的时哪个数字 现在我们可以转换一下题目   现有n个箱子,m种物体  现要将m种物体放入n个箱子中  如果之前放过同一种物体 那个箱子相当与放了一个 空;

首先我们第一位不能为空 那么就有M 种可能   接下来我们就有n-1个箱子要放m-1个东西

 那么我们假如全部都为空 (全填与第一个相同的数) 有一种

如果我要放k种物体   那么我们可以从 n-1个箱子中选出k个  即\binom{n-1}{k}种   那么k种物体的顺序不同也是不同 即{A_{m-1}}^{k}

那么答案就是   ans=m*\sum_{k=0}^{k=min(n-1,m-1)}\binom{n-1}{k}{A_{m-1}}^{k};   

代码:

#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#include<map>
#include<string>
#include<iostream>
#include<set>
using namespace std;
typedef long long ll;
ll mod=998244353;
ll inv[1000006];
ll ji[1000006];
ll mo(ll a,ll pp){
    if(a>=0&&a<pp) return a;
    a%=pp;
    if(a<0) a+=pp;
    return a;
}
ll powmod(ll a,ll b,ll pp){
    ll ans=1;
    for(;b;b>>=1,a=mo(a*a,pp)){
        if(b&1) ans=mo(ans*a,pp);
    }
    return ans;
}
int main()
{
    for(int i=1;i<=1000005;i++)
    {
        inv[i]=powmod(i,mod-2,mod);
    }
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        ll n,m;
        scanf("%lld%lld",&n,&m);
        ll len=min(n-1,m-1);
        ll C=1;
        ll A=1;
        ll ans=1;
        for(int i=1;i<=len;i++)
        {
            ll num=(n-i)%mod;
            C=((C*num)%mod*inv[i])%mod;
            num=(m-i)%mod;
            A=(A*num)%mod;
            ans=(ans+(A*C)%mod)%mod;
        }
        ans=(ans*(m%mod))%mod;
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lkaicheng/article/details/81415570
今日推荐