题意:
有n个set(元素没有数量之分),有无限个1~m,第i次操作可以从中选一个元素往set i~n里面插入
求有多少种可能结果(只要有一个set不是完全相同)
解析:
方案问题之所以复杂往往是缺失了正确的理解,就像上一篇讲的矩阵转图论再转dp一样
这道题如果从前往后推或者接下去找规律的话就很难做了,换种思路,如果我们选出总共i种元素来放的话,每种元素只有第一次放才有作用,所以我们计算第一次出现位置即可
对于n,m选i种元素的情况
- m选i:C(m,i)
- n选i放:C(n,i)
- i种元素顺序:A(i,i)
得出:Π(m-i+1~m)*Π(n-i+1~n)/i!
但是这个只是理想情况而已,因为题目的意思,第一个放的位置并无影响,所以所有情况都*i/n
得出:Π(m-i+1~m)*Π(n-i+1~n-1)/(i-1)!
当然,我们只要对于i==1的情况赋特殊初值就可以解决这个问题
而i的范围是1~min(m,n),对于不同的i是可以递推的,所以时间就是min(m,n)了
代码:
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const D mod=998244353;
const int N=1e6;
D inv[N+9];
void ininv(){
mmm(inv,0);
inv[1] = 1;inv[0]=1;
for(int i = 2; i <= N+1 ; i++)
inv[i] = ( mod - mod / i ) * inv[ mod % i ] % mod;
}
int main(){
ininv();
int t=read(),cas=0;
while(t--){
D n=read(),m=read();m=m%mod,n=n%mod;
D i,ans=m,sum =m;
for(i=2;i<=min(n,m);i++){
sum=sum*(m-i+1)%mod*(n-i+1)%mod*inv[i-1]%mod;
ans=(ans+sum)%mod;
}
printf("Case #%d: %lld\n", ++cas, ans);
}
}