UVa 11610 Reverse Prime(树状数组+二分)

来源:互联网 发布:Mac 变速播放器 编辑:程序博客网 时间:2024/06/10 21:22

有一些7位数,倒转过之后都是小于10^6的素数,叫做倒素数。把这些倒素数按大小排列,分别求出每个倒素数的素因子个数(比如24是2,2,2,3,共4个);

先有两种操作:

1.q i:查询从第0个到第i个倒素数的所有素因子之和;

2.d x:从这些倒素数中删除x,剩下的倒素数按大小重新排列。


首先把每个倒素数除以10,然后因子个数都先加上2,消除末尾0(题目也是有点无聊);

delete操作add函数可以完成;

主要是删除之后剩下的数重新排列有点麻烦,但是不是不可解决:

1.建立一个维护名次的树状数组,sum(x)就是x的名次,所以初始化的之和每个点都直接更新1,删除的时候直接更新-1;

2.询问真的名次时,则需要二分查找出初始名次,sum函数求出来的数组必然有序,所以需要一个类似于upper_bound的函数(同一值的点必然最后一个是合法的)。


要实现lower_bound和upper_bound的功能只差在等号加在哪个if上。


#include <algorithm>#include <stdlib.h>#include <iostream>#include <string.h>#include <stdio.h>#include <math.h>using namespace std;#define MAXN 670000#define lowbit(x) (x & -x)#define bin(x) (lower_bound(rev, rev + tot, x) - rev)/*.............................................PRIME SIEVE.............................................*/const int maxn = 1000100;const int prin = 300000;int prime[prin];///仅包含奇数,isprime[k]代表2*k+3bool isprime[maxn>>1];int ptop = 0;void sieve(){        memset(isprime, true, sizeof(isprime));        prime[0] = 2;        int sq = sqrt(maxn);        for(int i = 3; i < maxn; i += 2)        {                if(isprime[(i-3)>>1])                {                        if(i <= sq+3)                        {                                for(int j = i*i; j < maxn; j += 2*i)                                {                                        isprime[(j-3)>>1] = false;                                }                        }                        prime[++ptop] = i;                }        }        return ;}/*.............................................PRIME SIEVE.............................................*/int rev[MAXN], fac[MAXN], ss[MAXN], in[MAXN];int tot;int sum(int a[], int i){    int ret = 0;    while(i > 0) ret += a[i], i -= lowbit(i);    return ret;}int add(int a[], int i, int val){    while(i <= tot) a[i] += val, i += lowbit(i);}int get_rev(int x){    int ret = 0;    for(int i = 0; i < 6; i++) ret *= 10, ret += x % 10, x /= 10;    return ret;}void init(){    sieve();    for(tot = 0; prime[tot] < 1000000; tot++) rev[tot] = get_rev(prime[tot]);    sort(rev, rev + tot);    for(int i = 0; i < tot; i++)    {        fac[i] = 2; //已去掉末尾0        int tmp = rev[i];        for(int j = 0; prime[j] <= sqrt(tmp + 10); j++)            while(tmp % prime[j] == 0) tmp /= prime[j], fac[i]++;        if(tmp > 1) fac[i]++;    }    for(int i = 0; i < tot; i++) add(ss, i + 1, fac[i]), add(in, i + 1, 1);}int find(int x, int l = 1, int r = tot + 1){    if(l >= r) return r;    int m = (l + r) >> 1;    if(sum(in, m) >  x) return find(x, l, m);    if(sum(in, m) <= x) return find(x, m + 1, r);}char op[4];int x;int main(){//    freopen("D.in", "r", stdin);//    freopen("D.out", "w", stdout);    init();    while(~scanf("%s%d", op, &x))    {        if(op[0] == 'q')        {            int id = find(x + 1) - 1;            printf("%d\n", sum(ss, id));        }        if(op[0] == 'd')        {            x /= 10;            int id = bin(x);            add(ss, id + 1, -fac[id]);            add(in, id + 1, -1);        }    }    return 0;}


0 0
原创粉丝点击