1. 程式人生 > >Newcoder 144 C.Generation I(組合數學)

Newcoder 144 C.Generation I(組合數學)

Description

初始有nn個空集編號為11~nnnn次操作,第ii次操作會對所有編號介於[i,n][i,n]之間的集合插入一個介於[1,m][1,m]之間的整數xx,問有多少種方案使得nn次操作後集合狀態不同

Input

第一行一整數TT表示用例組數,每組用例輸入兩個整數n,mn,m

(1T20,1n,m1018,1min(n,m)106)(1\le T\le 20,1\le n,m\le 10^{18},1\le min(n,m)\le 10^6)

Output

輸出方案數,結果模1

09+710^9+7

Sample Input

2 2 2 3 4

Sample Output

Case #1: 4 Case #2: 52

Solution

最後一個集合有kk個數字且這kk個數字隨著集合編號上升依次出現的方案數為AmkA_m^k,而第一個數字必然在第11個集合出現,剩下k1k-1個數字只會在第2,....,n2,....,n個集合中依次出現,方案數Cn1k1C_{n-1}^{k-1},故答案為i=1min(n,m)AmiCn1i1\sum\limits_{i=1}^{min(n,m)}A_m^iC_{n-1}^{i-1}

,由於min(n,m)105min(n,m)\le 10^5,直接計算即可

Code

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
#define maxn 1000005
#define mod 998244353
int inv[maxn];
int mul(int x,int y)
{
	ll z=1ll*x*y;
	return z-z/mod*mod; 
}
int add(int x,int y)
{
	x+=y;
	if(x>=mod)x-=mod;
	return x;
}
void init(int n=1e6)
{
	inv[1]=1;
	for(int i=2;i<=n;i++)inv[i]=mul(mod-mod/i,inv[mod%i]);
}
int main()
{
	init();
	int T,Case=1;
	ll n,m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld",&n,&m);
		int ans=m%mod;
		int a=m%mod,b=1;
		for(int i=2;i<=min(n,m);i++)
		{
			a=mul(a,(m-i+1)%mod);
			b=mul(b,mul((n-i+1)%mod,inv[i-1]));
			ans=add(ans,mul(a,b));
		}
		printf("Case #%d: %d\n",Case++,ans);
	}
	return 0;
}