UVA11610(欧拉筛+二分+BIT)

16 篇文章 0 订阅
14 篇文章 1 订阅

看到数论其实就有点虚了。。还好欧拉筛自己还是会的。。

其实很明显可以看出最后一个数位一定是0,那么在处理的时候先提出个2和5,把1e7降成1e6

然后在1e6内筛出素数,题中的reverse prime就是把这些素数翻转后加0,然后排序。。

当然我不是很想排序。。所以直接枚举了各个数去翻转,免去了排序。。

然后就是把这些数的因子提出来。。在提的过程中可以判断剩下的数是不是素数。。这样可以把O(n^2) 降为O(nsqrt(n))

然后就是按照个数开区间,用BIT维护素数个数,再另开一个BIT维护个数前缀和,方便确定求和区间,由于有单调性,求和时直接二分确定区间即可。对于删除可以直接二分修改。。





#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define eps 1e-8
#define inf 1000000007
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define ls T[i<<1]
#define rs T[i<<1|1]
#define op T[i]
#define mid (x+y>>1)
#define NM 100005
#define nm 1000005
#define pi 3.141592653
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}


int n,m,tot,_t,a[NM],b[NM],c[NM],d[NM];
int prime[NM];
bool v[nm];
char _s[10];
void mod(int x,int t){for(;x<=n;x+=lowbit(x))c[x]+=t;}
int sum(int x,int s=0){for(;x;x-=lowbit(x))s+=c[x];return s;}
void _mod(int x,int t){for(;x<=n;x+=lowbit(x))d[x]+=t;}
int _sum(int x,int s=0){for(;x;x-=lowbit(x))s+=d[x];return s;}

void Euler(){
	m=1e6;tot=0;v[1]=true;
	inc(i,2,m){
		if(!v[i])prime[++tot]=i;
		inc(j,1,tot){
			if(i*prime[j]>m)break;
			v[i*prime[j]]=true;
			if(i%prime[j]==0)break;
		}
	}
}

int find(int x){
	int l=1,r=tot,ans;
	while(l<=r){
		int t=l+r>>1;
		if(_sum(t)>=x){ans=t;r=t-1;}
		else l=t+1;
	}
	//printf("%d ",ans);
	return ans;
}

int main(){
	//freopen("data.in","r",stdin);
	Euler();
	inc(i,m/10,m-1){
		int tmp[10];mem(tmp);
		for(int t=i,k=0;t;t/=10)tmp[++k]=t%10;
		int t=0;
		inc(j,1,6)t=t*10+tmp[j];
		if(!v[t])b[++n]=i;
	}
	//printf("%d %d\n",tot,n);
	inc(i,1,n){
		int t=b[i];a[i]=2;
		inc(j,1,tot){
			while(t%prime[j]==0){t/=prime[j];a[i]++;}
			if(!v[t]){a[i]++;break;}
		}
		mod(i,a[i]);_mod(i,1);
	}
	//inc(i,1,10)printf("%d ",a[i]);putchar('\n');
	while(~scanf("%s",_s)){
		_t=read();
		if(_s[0]=='q')printf("%d\n",sum(find(_t+1)));
		else{
			int t=lower_bound(b+1,b+1+n,_t/10)-b;
			mod(t,-a[t]);_mod(t,-1);
		}
	}
	return 0;
}



Reverse Prime

Input: Standard Input

Output: Standard Output

 

There are a few 7 digit positive numbers whose reverse number is a prime number and less than 10^6.  For example: 1000070, 1000090 and 1000240 are first few reverse prime numbers because all of the numbers are 7 digit numbers whose reverse number is a prime number and less than 10^6. You have to find out all the 7 digit reverse prime numbers and also it’s number of prime factors. Prime factors of a positive integer are the prime numbers that divide into that integer exactly, without leaving a remainder. For example, prime factors of 24 are 2, 2, 2 and 3.

 

In this problem, you’ll encounter 2 types of input –

 

Query:

This type of input will be formatted like this – “q i. For this input, you have to calculate the cumulative summation of the number of prime factors of reverse prime numbers from 0-th to i-th index.

 

Deletion:

This type of input will be formatted like this – “d reverse_prime. For this input, you have to delete reverse_prime from the set and update your summation. No output is required in such cases.

 

It is guaranteed that i will be a valid index and reverse_prime will be a valid 7 digit reverse prime number. It is also guaranteed that no two reverse_prime will be same.

 

There will be at most 71000 query lines and 3500 deletion lines in the data set. The program will terminated by EOF.

 

 

Sample Input                                                                               Output for Sample Input

q 0

q 1

q 2

d 1000070

d 1000090

q 0

d 1000240

q 0

q 1

4

10

16

6

3

7

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值