zoukankan      html  css  js  c++  java
  • codefoces E

    题目链接:http://codeforces.com/contest/1559/problem/E

    先不考虑 (gcd) 的限制,设 (dp[i][j]) 表示前 (i) 个数和为 (j) 的方案数

    容斥掉 (gcd) 不为 (1) 的答案,那就是考虑只选 (gcd) 的倍数的数的答案,容斥系数是莫比乌斯函数

    时间复杂度 (O(nmln(m)))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxm = 100010;
    const int maxn = 55;
    const int M = 998244353;
    
    int n, m, cnt = 0;
    int a[maxm * 2], l[maxm][maxn], r[maxm][maxn];
    int dp[maxn][maxm], f[maxm], sum[maxn][maxm];
    
    int prime[maxm], is_prime[maxm], mu[maxm];
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	mu[1] = 1;
    	for(int i = 2; i <= 100000; ++i){
    		if(!is_prime[i]){
    			prime[++cnt] = i;
    			mu[i] = -1;
    		}
    		for(int j = 1 ; j <= cnt && prime[j] * i <= 100000 ; ++j){
    			is_prime[i * prime[j]] = 1;
    			if(i % prime[j] == 0) {
    				mu[i * prime[j]] = 0;
    				break;
    			} else {
    				mu[i * prime[j]] = -mu[i];
    			}
    		}
    	}
    	
    	n = read(), m = read();
    	for(int i = 1 ; i <= n ; ++i) l[1][i] = read(), r[1][i] = read();
    	
    	memset(f, 0, sizeof(f));
    	for(int g = 2 ; g <= m ; ++g){
    		int tot = 0;
    		for(int i = 0 ; i <= m ; i += g){
    			a[++tot] = i;
    		}
    		for(int i = 1 ; i <= n ; ++i){
    			int p = lower_bound(a + 1, a + 1 + tot, l[1][i]) - a;
    			if(p == tot + 1) p = tot;
    			l[g][i] = a[p];
    			p = lower_bound(a + 1, a + 1 + tot, r[1][i]) - a;
    			if(p == tot + 1) p = tot;
    			r[g][i] = a[p];
    			if(r[g][i] > r[1][i]) r[g][i] -= g;
    		}
    	}
    	
    	int res = 0;
    	
    	for(int g = 1 ; g <= m ; ++g) { // gcd
    		int tmp = g;
    		int cnt_fac = 0;
    		int mx = 0; int up = (int)sqrt(g+0.5);
    		for(int j = 1 ; j <= cnt && prime[j] <= up ; ++j){
    			if(tmp % prime[j] == 0) ++cnt_fac;
    			int cnt_p = 0;
    			while(tmp % prime[j] == 0){
    				tmp /= prime[j];
    				++cnt_p;
    			}
    			mx = max(mx, cnt_p);
    		}
    		if(tmp > 1) ++cnt_fac, mx = max(mx, 1);
    		
    		for(int i = 1 ; i <= n ; ++i){
    			for(int j = g ; j <= m ; j += g) dp[n][j] = 0;	
    		}
    		
    		dp[0][0] = 1;
    		sum[0][1] = 1; int down = 0;
    		for(int i = g ; i <= m ; i += g) sum[0][i+1] = sum[0][i-g+1];
    		for(int i = 1 ; i <= n ; ++i){
    			down += l[g][i]; 
    			if(l[g][i] > r[g][i]) continue;
    			for(int j = g ; j <= m ; j += g){
    				dp[i][j] = ((sum[i-1][max(0, j-l[g][i]+1)] - sum[i-1][max(0, j-r[g][i]-g+1)]) % M + M) % M;
    				sum[i][j+1] = (sum[i][j-g+1] + dp[i][j]) % M;
    			}
    		}
    		
    		for(int i = g ; i <= m ; i += g) {
    			f[g] = (f[g] + dp[n][i]) % M;
    		}
    		
    		res = ((res + mu[g] * f[g]) % M + M) % M;
    	}
    	printf("%d
    ", res);
    	return 0;
    }
    
  • 相关阅读:
    集群间Session共享问题解决方案
    session原理及实现共享
    【单点登录】【两种单点登录类型:SSO/CAS、相同一级域名的SSO】
    HashMap与ConcurrentHashMap的区别
    Java的文件读写操作
    Spring之ClassPathResource加载资源文件
    3万的支付订单请求并发解决方案
    java中的队列
    互联网应用在高并发
    四种Java线程池用法解析
  • 原文地址:https://www.cnblogs.com/tuchen/p/15164754.html
Copyright © 2011-2022 走看看