输入:
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个 即种 那么k种物体的顺序不同也是不同 即
种
那么答案就是 ans=m*;
代码:
#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;
}