题意:
有nnn种食物,分给kkk个队,每个队拿取食物时每种食物最多拿一份,可以不拿,当k=1,2....mk=1,2....mk=1,2....m时,有多少种分配方法使得所有食物都分配给了所有队?(∑i=1na[i]≤100000)(\sum_{i=1}^{n}a[i]\leq100000)(∑i=1na[i]≤100000)
Solution:
设max1=max(a[i])max1=max(a[i])max1=max(a[i])
既然每个队最多每种拿一份,那么当k≥max1k\geq max1k≥max1时才可能分配完全,此时每种食物iii必然分配给kkk个队的是a[i]a[i]a[i]个1和k−a[i]k-a[i]k−a[i]个0,这样每个队在这种食物的分配可能就有Cka[i]C_{k}^{a[i]}Cka[i]种,那么总可能即Πi=1nCka[i]\Pi_{i=1}^{n}C_{k}^{a[i]}Πi=1nCka[i],这样的话计算一个kkk的时间复杂度是O(n)O(n)O(n),那么总复杂度是O(nm)O(nm)O(nm)
正解只是加了一个小优化,因为a[i]a[i]a[i]总和不超过100000100000100000,这样必然会有一些a[i]a[i]a[i]一样的,于是把这些a[i]a[i]a[i]一样的写在一起,他们的乘积就可以用快速幂,我用了一个mapmapmap保存,每次都遍历完mapmapmap的元组,时间复杂度是O(能过)O(能过)O(能过),用了800+ms,把mapmapmap写成数组加桶形式应该会更快
#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;
}
组合数学在食物分配问题的应用
本文探讨了一种特定的食物分配问题,通过组合数学的方法计算不同队伍间多种食物的分配方案数量。考虑到每种食物每队最多只能拿取一份的情况,文章提出了一种基于快速幂优化的高效算法。
1134

被折叠的 条评论
为什么被折叠?



