本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
题目链接
题目
During your participation in this competition, Shinyruo is preparing to order KFC for the offline competition next week.
There are nn kinds of foods in KFC, and he plans to order aiai number of the i-th food for every i∈[1,n]. Due to shortage of manpower, the total number of all kinds of foods is no larger than 100000.
After the competition, he will hand all the KFC out to kk teams. Each team can get different kinds of foods but for each kind it can get one at most.
Now Shinyruo wants to know the number of ways to hand the desserts out. As he doesn't know the number of participating teams, you need to calculate the answers for k=1,2,⋯,m.
As the answer can be large, print it modulo 998244353.
题目大意
有 种东西,第 种有 个。有若干个相同的袋子,袋子里可以随便放物品,但是不能存在一个袋子里有两个或以上同一种物品的情况。
对于 ,求当有 个袋子,放物品的方案数。
思路
容易发现当有 个袋子时,第 个物品存放的方案即 ,且 个物品的存放方案相互独立。则答案为 。
怎么求组合数取余呢?显然 ,我们只需要对 到 之间的数的阶乘都求出他们的阶乘和阶乘的逆元即可快速求阶乘了。显然 是质数,所以可以用费马小定理先求出 的逆元。 当我们知道 的逆元是 时,即我们已经知道了
两边同时乘 即可得到
倒序递推即可。
然后发现直接暴力会 TLE,考虑优化。因为 ,所以互不相同的 不超过 个。先统计不同值的 的数量,统计答案时乘组合数的若干次方即可。
代码
#include<bits/stdc++.h>
using namespace std;
using LL=long long;
const int N=100005;
const int p=998244353;
const int mod=998244353;
int a[100005],b[100005],cnt[100005],tot;
LL fac[N],inv[N];
LL poww(LL a,LL b) {
LL ans=1;
for (;b;b>>=1,a=a*a%mod)
if (b&1) ans=ans*a%mod;
return ans;
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
fac[0]=1;
for (int i=1;i<=50000;++i) fac[i]=fac[i-1]*i%mod;
inv[50000]=poww(fac[50000],mod-2);
for (int i=50000;i>=1;--i) inv[i-1]=inv[i]*i%mod;
for (int i=1;i<=n;++i) scanf("%d",&a[i]);
sort(a+1,a+n+1);
a[0]=-1;
for (int i=1;i<=n;++i)
if(a[i] != a[i-1])
{
b[++tot]=a[i];
cnt[tot]=1;
}
else cnt[tot]++;
for(int i=1;i<=m;i++)
{
LL ans=1;
if (i<a[n]) printf("0\n");
else
{
for (int j=1;j<=tot;j++)
ans=(ans*poww(fac[i]*inv[b[j]]%p*inv[i-b[j]]%p,cnt[j]))%p;
printf("%lld\n",ans);
}
}
}