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 ≤ 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.
示例1
输入
2
2 2
3 4
输出
Case #1: 4
Case #2: 52
这道题可以这么理解:(完全就是高中排列组合数学题嘛!)
相当于染色问题。每一次染色就相当于从某个位置到末端扫一遍
然后假设一共是m个颜色,假设染 k 种颜色 就是C(m,k)
第一个位置肯定是要染色的,有k种选择方法。然后剩下的,有的需要染,有的不需要就是在n-1个位置里选出k-1个位置为开头进行染色,然后具体怎么染色还要有(k-1)!
所以 就是 C(m,k)*k*C(n-1,k-1)*(k-1) !, k从1到min(位置数,总颜色数) 的上面算式的总和。
然后通过递推推出公式就好了。就是从k推出k+1。
还有一种想法:就是隔板法。
假设全部都是一种颜色,无需隔板;假设有两种颜色,枚举隔板出现的位置(隔板就是从哪里开始改变的位置),此时有一个隔板;假设有三种颜色,就是两个隔板,依次这样子。
思路一代码:(队友的)
#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
*/