zoukankan      html  css  js  c++  java
  • UVA11610 Reverse Prime

    Description

    洛谷传送门

    有一些小于(10^6)的质数,你需要把它们倒过来并补成一个 7 位数,例如质数 700001,将转变成 1000070,900001,将转变为 1000090,你要将转变后的数存成一个序列。输入有两种操作:

    1. 查询:输入q i,你需要输出这个序列中前 (i) 小(包含 (i) )的数的质因数个数的和。(注意是个数)

    2. 删除:输入d i,你需要把序列中第 (i) 小的数删除。

    有多组输入

    注意下角标从0开始

    Solution

    这道题我们考虑用树状数组解,首先我们用线性筛算出小于(10^6)的质数,并将这些质数倒过来补成 7 位数并存到一个数组里(比如说 (a) 数组),然后对 (a) 数组进行排序,再计算出 (a) 数组中每一个 7 位数的质因数个数存到另一个数组里,这样我们的预处理部分就完成了。

    再来说如何做树状数组,我们需要两个树状数组,一个维护当前 (i) 节点之前有多少个数,另一个维护 (i) 节点之前所有数的质因数个数,我们需要将所有经过转变后的数都加进树状数组里,查询时利用二分查找一个有 (i) 个比本身小的数,删除时只需要把 -1 加进第一个树状数组,把该点的质因数个数的相反数加进第二个数状数组即可。

    有一些小技巧,当计算每一个转换后的数的质因数个数时,由于质数最大也小于 7 位数,变为 7 位数至少多一个 0,所以直接让每一个数的质因数个数的初值为 2(10 可以拆成 (2 * 5)),质数转换时只转换为为 6 位数就可以了,可以看代码理解一下。

    Code

    #include <iostream>
    #include <algorithm>
    #include <map>
    #define ll long long //答案是long long
    #define N 1000000	 //质数的最大范围
    #define M 100010	 //小于10^6的质数个数是78498个,这里开到100010
    
    using namespace std;
    
    map<int, int> mp;					//由于数据范围过大,需要开map,其实也可以用离散化,不过我太蒻了,所以用的map
    int p[N + 10], mindiv[N + 10], tot; //线性筛用的,tot为质数个数
    int a[N + 10];						//记录转换后的7位数
    int c1[N + 10], c2[N + 10];			//树状数组,c1记录数的个数,c2记录质因数个数
    int c[M];							//记录每一个数的质因数个数
    
    //----------------------树状数组模板,不细讲了,有两个树状数组,所以要写两遍.
    int lowbit(int k){
    	return k & (-k);
    }
    
    void add1(int x, int y){
    	for(int i = x; i <= N; i += lowbit(i)) //没有固定数据范围,所以要到最大值
    		c1[i] += y;
    }
    
    void add2(int x, int y){
    	for(int i = x; i <= N; i += lowbit(i))
    		c2[i] += y;
    }
    
    ll getsum1(int x){
    	ll ans = 0;
    	for(int i = x; i > 0; i -= lowbit(i))
    		ans += c1[i];
    	return ans;
    }
    
    ll getsum2(int x){
    	ll ans = 0;
    	for(int i = x; i > 0; i -= lowbit(i))
    		ans += c2[i];
    	return ans;
    }
    
    //----------------------线性筛模板,也不讲了
    void prime(){
    	for(int i = 2; i <= N; i++){
    		if(!mindiv[i]){
    			mindiv[i] = i;
    			p[++tot] = i;
    		}
    		for(int j = 1; j <= tot && p[j] * i <= N && p[j] <= mindiv[i]; j++)
    			mindiv[p[j] * i] = p[j];
    	}
    }
    
    //----------------------计算每一个经过转换后的6位数的质因数个数,至于为什么是6位数,请见代码上方的解释
    void devide(int i){
    	c[i] = 2;
    	int tmp = a[i];
    	for(int j = 1; j <= tot && p[j] * p[j] <= tmp; j++) //小优化,如果p[j]*p[j]>tmp,就不会再有tmp的质因数
    		while(tmp % p[j] == 0)
    			c[i]++, tmp /= p[j];
    	if(tmp > 1) c[i]++;
    }
    
    //----------------------zh=转换,把每一个质数转换为新的6位数,值存在a数组中
    int zh(int x){
    	int ans = 0, t = 0;
    	while(x)
    		t++, ans = ans * 10 + x % 10, x /= 10;
    	t = 6 - t;
    	while(t)
    		ans *= 10, t--;
    	return ans;
    }
    
    //----------------------预处理
    void prework(){
    	for(int i = 1; i <= tot; i++) //转换
    		a[i] = zh(p[i]);
    	sort(a + 1, a + tot + 1);	   //从小到大排序
    	for(int i = 1; i <= tot; i++) //存到map中
    		mp[a[i]] = i;
    	for(int i = 1; i <= tot; i++) //计算每一个转换后的数的质因数个数
    		devide(i);
    }
    
    int main(){
    	prime();
    	prework();
    	for(int i = 1; i <= tot; i++){ //初始化树状数组
    		add1(i, 1);
    		add2(i, c[i]);
    	}
    	char ch[5];
    	int x;
    	while(scanf("%s%d", ch, &x) != EOF){
    		if(ch[0] == 'q'){
    			x++;					 //注意,题目中下角标从0开始,这里从1开始算,所以加1
    			int l = 1, r = tot, mid; //二分找答案,mid就是答案
    			while(l <= r){
    				mid = (l + r) >> 1;
    				ll tmp = getsum1(mid);
    				if(tmp == x) break;
    				if(tmp < x) l = mid + 1;
    				else r = mid - 1;
    			}
    			printf("%lld
    ", getsum2(mid));
    		}else{ //删数时因为转换的是6位数,所以要/10
    			add1(mp[x / 10], -1);
    			add2(mp[x / 10], -c[mp[x / 10]]);
    		}
    	}
    	return 0;
    }
    

    End

    本文来自博客园,作者:xixike,转载请注明原文链接:https://www.cnblogs.com/xixike/p/15354647.html

  • 相关阅读:
    SSH Config 那些你所知道和不知道的事 (转)
    解决npm ERR! Unexpected end of JSON input while parsing near的方法
    ES查询-term VS match (转)
    ES查询-match VS match_phrase
    安装使用aria2下载百度网盘内容(转)
    基于CSS3鼠标滑过放大突出效果
    基于jQuery的新浪游戏首页幻灯片
    基于animation.css实现动画旋转特效
    基于jQuery左右滑动切换特效
    基于html5顶部导航3D翻转展开特效
  • 原文地址:https://www.cnblogs.com/xixike/p/15354647.html
Copyright © 2011-2022 走看看