• CCPC 2021威海 - G. Shinyruo and KFC(组合数,小技巧)


    G. Shinyruo and KFC

    题意
    一共有 n n n 种食物,每种食物有 a i a_i ai 个。食物个数总和不超过 1 0 5 10^5 105
    现在要把这些食物分给 k k k 个人,每个人可以拿多种事物,但每种食物最多拿 1 个。
    对于 k k k 从 1 到 m m m,分别输出食物分配方案。
    答案模 998244353 998244353 998244353
    1 ≤ m , n ≤ 5 ⋅ 1 0 4 1 \le m,n \le 5 \cdot 10^4 1m,n5104
    0 ≤ a i ≤ 1 0 5 ,   ∑ i = 1 n a i ≤ 1 0 5 0\le a_i\le 10^5,\ \sum_{i=1}^n a_i\le 10^5 0ai105, i=1nai105

    思路
    对于一种食物共有 a i a_i ai 个,分给 k k k 个人,每人最多分一个,那么分配方案为 C ( k , a i ) C(k, ai) C(k,ai)
    那么 n 种食物,分给 k 个人总的分配方案为: ∏ i = 1 n C ( k , a i ) \prod_{i=1}^{n} C(k, a_i) i=1nC(k,ai)
    再遍历 m 个人,这样的话时间复杂度最低为 O(n * m),超时。

    而题目中说 ai 总和不超过 1e5,那么 ai 的种类数就在 1 e 5 \sqrt {1e5} 1e5 级别,对于重复的直接用快速幂求幂次。
    预处理逆元求组合数。

    这样时间复杂度降为: O ( m n   l o g n ) O(m \sqrt n \ logn) O(mn  logn)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    
    #define Ios ios::sync_with_stdio(false),cin.tie(0)
    #define int long long
    #define fi first
    #define se second
    #define endl '\n'
    map<int,int> mp;
    
    const int N = 200010, mod = 998244353;
    int T, n, m;
    int a[N];
    struct node{
    	int x, cnt;
    }b[N];
    int fac[N], inv[N], finv[N];
    
    int qmi(int x, int y)
    {
    	int ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x % mod;
    		x = x*x % mod;
    		y >>= 1;
    	}
    	return ans;
    }
    
    void init(){
    	fac[0]=inv[0]=inv[1]=finv[0]=finv[1]=1ll;
    	for(int i=1;i<N;i++)fac[i]=fac[i-1]*i%mod;
    	for(int i=2;i<N;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    	for(int i=2;i<N;i++)finv[i]=finv[i-1]*inv[i]%mod;
    }
    
    inline int C(int a,int b){
    	if(b>a)return 0;
    	else return fac[a]*finv[a-b]%mod*finv[b]%mod;
    }
    
    signed main(){
    	Ios;
    	cin >> n >> m;
    	for(int i=1;i<=n;i++) cin >> a[i], mp[a[i]]++;
    	
    	int cnt = 0;
    	for(auto it : mp)
    	{
    		cnt++;
    		b[cnt] = {it.first, it.second};
    	}
    	
    	init();
    	
    	for(int i=1;i<=m;i++)
    	{
    		int ans = 1;
    		for(int j=1;j<=cnt;j++)
    		{
    			ans = ans * qmi(C(i, b[j].x), b[j].cnt) % mod;
    		}
    		cout << ans << endl;
    	}
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68

    经验

    • 如果 n 个数的总和不超过 m,那么这些数的种类个数在 m \sqrt m m 级别。
  • 相关阅读:
    Daffodil for Visual Studio
    uni-app进阶之https请求方式/状态管理【day11】
    axios 请求拦截器&响应拦截器与router的导航守卫
    Json(一种数据格式,key:value)
    MySQL运算符
    腾讯云部署springboot jar包过程
    全套3D游戏建模自学资料
    Nodejs安装教程
    java restfull请求方式 (get、post、put 、delete、patch)
    LabVIEW开发多速率实时混合仿真
  • 原文地址:https://blog.csdn.net/Mr_dimple/article/details/125624979