zoukankan      html  css  js  c++  java
  • Codeforces Round #738 (Div. 2) E.Mocha and Stars 容斥+DP

    Codeforces Round #738 (Div. 2) E.Mocha and Stars 容斥+DP

    题意

    求满足如下三个条件的序列(a)的个数

    1.(forall i (1le ileq n),a_i in [l_i,r_i])

    2.(sum_{i=1}^n a_i leq m)

    3.(gcd(a_1,a_2...a_n) = 1)

    [2 leq n leq 50,1 leq m leq 10^5\ 1 leq l_i leq r_i leq m ]

    分析

    首先考虑第3个条件 这类题的通常做法是枚举序列的(gcd)

    于是有经典的容斥:

    [ans = sum_{i=1}mu(i)f(i) ]

    于是此题可以用枚举(gcd)处理掉条件3

    注意到(n)的规模只有50,于是可以对每次进行dp:

    若当前枚举的gcd = i,那么每个数可以选择贡献几个(i)

    对于条件2,可以知道所有数加起来最多贡献(xileq m => x leq lfloorfrac{m}{i} floor)

    对于条件1,可以知道每个数最少贡献(lceil frac{a_j}{i} ceil) 最多贡献(lfloorfrac{a_j}{i} floor)

    于是可以令(dp[i][j])表示前(i)个数一共贡献(j)个的方案数

    [dp[i][j] = sum_{k = L}^Rdp[i-1][k] ]

    可以预处理前缀和后(O(nlfloorfrac{m}{i} floor))转移

    代码

    #include<bits/stdc++.h>
    #define pii pair<ll,ll>
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    const int MOD = 998244353;
    
    inline int mul(int a,int b){
    	int res = (ll)a * b % MOD;
    	if(res < 0) res += MOD;
    	return res;
    }
    
    inline void add(int &a,int b){
    	a += b;
    	if(a >= MOD) a -= MOD;
    }
    
    inline void sub(int &a,int b){
    	a -= b;
    	if(a < 0) a += MOD;
    }
    
    
    
    const int maxn = 1e5 + 5;
    
    int prime[maxn], prime_tot;
    int is_prime[maxn];
    int mu[maxn];
    
    void pre_calc(int lim) {
        mu[1] = 1;
        for (int i = 2; i <= lim; i++) {
            if (!is_prime[i]) {
                prime[++prime_tot] = i;
                mu[i] = -1;
            }
            for (int j = 1; j <= prime_tot; j++) {
                if (i * prime[j] > lim) break;
                is_prime[i * prime[j]] = 1;
                if (i % prime[j] == 0) {
                    mu[i * prime[j]] = 0;
                    break;
                }
                else mu[i * prime[j]] = -mu[i];
            }
        }
    }
    
    
    
    int main(){
    	pre_calc(maxn - 3);
    	int n = rd();
    	int m = rd();
    	vector<int> l(n + 1),r(n + 1);
    	for(int i = 1;i <= n;i++)
    		l[i] = rd(),r[i] = rd();
    	int tot = 0;
    	for(int i = 1;i <= m;i++){
    		int lim = m / i;
    		int suml = 0;
    		for(int j = 1;j <= n;j++)
    			suml += (l[j] - 1) / i + 1;
    		if(suml > lim) continue;
    		vector<int> dp(lim + 1),sum(lim + 1),v(n + 1);
    		dp[0] = sum[0] = 1;
    		for(int j = 1;j <= n;j++){
    			int L = (l[j] + i - 1) / i;
    			int R = r[j] / i;
    			for(int k = 0;k <= lim;k++)
    				sum[k] = (dp[k] + (k - 1 < 0 ? 0 : sum[k - 1])) % MOD;
    			for(int k = 0;k <= lim;k++)
    				dp[k] = (MOD + (k - L < 0 ? 0 : sum[k - L]) - (k - R - 1 < 0 ? 0 : sum[k - R - 1])) % MOD;
    			//for(int k = 1;k <= lim;k++)
    				//sum[k] = sum[k - 1] + dp[k];
    		}
    		int tmp = 0;
    		for(int j = 1;j <= lim;j++)
    			add(tmp,dp[j]);
    		tot += mul(tmp,mu[i]),tot %= MOD,tot += MOD,tot %= MOD;
    	}
    	printf("%d",tot);
    }
    
  • 相关阅读:
    mysql时区设置
    jquery raidio buttion checked unchecked
    mysql定时备份
    丁香园 (http://www.dxy.cn)这个名字听着
    mysql backup solution
    mysql备份
    mysql编码设置
    在Ubuntu中通过源码安装编译安装软件(MySQL篇) 收藏
    社会化分享实现插件,分享到...
    ubuntu 小工具
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15150187.html
Copyright © 2011-2022 走看看