题意:
有 n n n种食物,分给 k k k个队,每个队拿取食物时每种食物最多拿一份,可以不拿,当 k = 1 , 2.... m k=1,2....m k=1,2....m时,有多少种分配方法使得所有食物都分配给了所有队? ( ∑ i = 1 n a [ i ] ≤ 100000 ) (\sum_{i=1}^{n}a[i]\leq100000) (∑i=1na[i]≤100000)
Solution:
设 m a x 1 = m a x ( a [ i ] ) max1=max(a[i]) max1=max(a[i])
既然每个队最多每种拿一份,那么当 k ≥ m a x 1 k\geq max1 k≥max1时才可能分配完全,此时每种食物 i i i必然分配给 k k k个队的是 a [ i ] a[i] a[i]个1和 k − a [ i ] k-a[i] k−a[i]个0,这样每个队在这种食物的分配可能就有 C k a [ i ] C_{k}^{a[i]} Cka[i]种,那么总可能即 Π i = 1 n C k a [ i ] \Pi_{i=1}^{n}C_{k}^{a[i]} Πi=1nCka[i],这样的话计算一个 k k k的时间复杂度是 O ( n ) O(n) O(n),那么总复杂度是 O ( n m ) O(nm) O(nm)
正解只是加了一个小优化,因为 a [ i ] a[i] a[i]总和不超过 100000 100000 100000,这样必然会有一些 a [ i ] a[i] a[i]一样的,于是把这些 a [ i ] a[i] a[i]一样的写在一起,他们的乘积就可以用快速幂,我用了一个 m a p map map保存,每次都遍历完 m a p map map的元组,时间复杂度是 O ( 能过 ) O(能过) O(能过),用了800+ms,把 m a p map map写成数组加桶形式应该会更快
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5e4+5;
const long long mod=998244353;
ll qpow(ll a,ll b)
{
ll ret=1,base=a;
while(b)
{
if(b&1) ret=ret*base%mod;
base=base*base%mod;
b>>=1;
}
return ret;
}
ll fac[100005],invfac[100005];
ll inv(ll k){return qpow(k,mod-2);}
ll C(int n,int m){return fac[n]*invfac[m]%mod*invfac[n-m]%mod;}
int n,m,a[N],max1;
map<int,int>map1;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
max1=max(max1,a[i]);
map1[a[i]]++;
}
for(int i=(invfac[0]=fac[0]=1);i<=N;i++)
{
fac[i]=fac[i-1]*i%mod;
invfac[i]=inv(fac[i]);
}
for(int i=1;i<max1;i++) printf("0\n");
for(int i=max1;i<=m;i++)
{
ll ans=1;
for(auto j:map1) ans=ans*qpow(C(i,j.first),1ll*j.second)%mod;
printf("%lld\n",ans);
}
return 0;
}