现在的位置: 首页 > 综合 > 正文

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

2019年02月11日 ⁄ 综合 ⁄ 共 2122字 ⁄ 字号 评论关闭

有一些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+3
bool 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;
}

抱歉!评论已关闭.