zoukankan      html  css  js  c++  java
  • UOJ188 Sanrd Min_25筛

    传送门


    省选之前做数论题会不会有Debuff啊

    这道题显然是要求(1)(x)中所有数第二大质因子的大小之和,如果不存在第二大质因子就是(0)

    线性筛似乎可以做,但是(10^{11})的数据范围让人望而却步,而杜教筛需要对(f(x))找到一个函数(g(x))做狄利克雷卷积成为一个好算前缀和的函数(h(x))相信各位是找不到这样一个函数的。所以考虑Min_25筛。但用Min_25筛还不知道要筛什么东西,故从Min_25筛最后的计算过程入手。

    Min_25筛的每一层递归中计算了两种数对答案的贡献:①当前被拼出的数乘上一个质数的若干次方产生的数的贡献;②当前被拼出的数乘上一个质数的若干次方再乘上其他质数产生的数的贡献。对于②的贡献我们递归处理,所以只需考虑①的情况。

    ①中,如果乘上的质数的指数(> 1),产生贡献的就是当前质因子,否则就是上一个被乘上的因子。上一个被乘上的因子在递归过程中已经传递了,所以我们只需要上一个被乘上的因子产生了多少次贡献,即在一段区间内共有多少个质数。所以筛出(forall x in [1,N] sumlimits_{i=1}^{frac{N}{x}} [i in Prime])就可以计算答案。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    inline int read(){
    	int a = 0;
    	char c = getchar();
    	while(!isdigit(c)) c = getchar();
    	while(isdigit(c)){
    		a = a * 10 + c - 48;
    		c = getchar();
    	}
    	return a;
    }
    
    const int MAXN = 1e6 + 7;
    int prm[MAXN] , cnt;
    bool nprm[MAXN];
    
    void init_prm(){
    	for(int i = 2 ; i <= 1e6 ; ++i){
    		if(!nprm[i])
    			prm[++cnt] = i;
    		for(int j = 1 ; i * prm[j] <= 1e6 ; ++j){
    			nprm[i * prm[j]] = 1;
    			if(i % prm[j] == 0) break;
    		}
    	}
    }
    
    int id1[MAXN] , id2[MAXN] , val[MAXN << 1] , f[MAXN << 1] , N , T , Cnt;
    
    int find(int x){return x <= T ? id1[x] : id2[N / x];}
    
    void init_Min25(){
    	T = sqrt(N); Cnt = 0;
    	for(int i = 1 , pi ; i <= N ; i = pi + 1){
    		int cur = N / i;
    		pi = N / cur;
    		val[cur <= T ? id1[cur] = ++Cnt : id2[pi] = ++Cnt] = cur;
    		f[Cnt] = cur - 1;
    	}
    	for(int i = 1 ; i <= cnt && prm[i] * prm[i] <= N ; ++i){
    		int p = find(prm[i - 1]);
    		for(int j = 1 ; val[j] >= prm[i] * prm[i] ; ++j){
    			int q = find(val[j] / prm[i]);
    			f[j] -= f[q] - f[p];
    		}
    	}
    }
    
    int solve(int x , int p){
    	if(prm[p] > x) return 0;
    	int sum = (f[find(x)] - f[find(prm[p - 1])]) * prm[p - 1];
    	for(int j = p ; j <= cnt && prm[j] * prm[j] <= x ; ++j){
    		int times = prm[j];
    		while(times * prm[j] <= x){
    			sum += solve(x / times , j + 1) + prm[j];
    			times *= prm[j];
    		}
    	}
    	return sum;
    }
    
    int work(){init_Min25(); return solve(N , 1);}
    
    signed main(){
    	init_prm();
    	cin >> N; --N; int sum = work();
    	cin >> N; cout << work() - sum;
    	return 0;
    }
    
    
  • 相关阅读:
    利用jQuery Ajax技术实现每隔5秒向某页面传值
    POJ 题目2761 Feed the dogs(主席树||划分树)
    【翻译自mos文章】将expdp的dmp文件从asm磁盘组里边放到本地文件系统里边
    【算法拾遗】最大数和最小数
    WinMain和MFC的差别
    3.1 The Interpolating Polynomial(站点)
    在VS中设置比较和谐的字体和颜色的方法
    获取微信服务器IP地址
    关于bcg库记忆界面的问题及其解决办法
    Objective-C基础笔记(8)Foundation常用类NSString
  • 原文地址:https://www.cnblogs.com/Itst/p/10660039.html
Copyright © 2011-2022 走看看