2013-09-22 21:01:03Morris

[UVA][BIT&線段樹] 11610 - Reverse Prime

Problem F
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

 

 

 


 

Problem Setter: Mohiul Alam Prince

Special Thanks: Sabbir Yousuf Sanny

題目描述:

找到所有 7 位的數字,這些數字必須符合反轉後是質數 (prime< 10^6),

並且從小開始編號 0th, 1st, ...

詢問有兩種
1) query i:詢問前 i 個數字的質因數個數總和,如果是 8=2^3,質因數個數即是 3。
2) delete number:刪除其中一個數字,保證一定符合條件的數字。而原本的排名會重新整理。

題目解法:

首先,必須先找到所有 7 位的數字,也就是將 10^6 內的質數反轉補 0 後的結果。

找完之後,考慮如何維護操作。

1) query

由於只查找 sigma(A[k]), 0 <= k <= i, 決定使用 binary indexed tree。

計算總和,同時在 delete 的時候,也會用到 binary indexed tree 調整。

2) delete

刪除某個數字時,考慮用 STL 的 map 找到刪除 k-th 個數字。

此時維護一個線段樹,用在 query i-th 時,查找到 j-th。

也就是刪除時,會將 A[k] = 0,但是查找 query i-th 時,必須找到 query j-th。

每筆操作都是 O(log n)

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <map>
#define maxL (1000000>>5)+1
#define GET(x) (mark[(x)>>5]>>((x)&31)&1)
#define SET(x) (mark[(x)>>5] |= 1<<((x)&31))
using namespace std;
int mark[maxL];
int pt = 0, p[100000];
int rp[100000], A[100000];
map<int, int> R;//mapped rp[]
void sieve() {
    register int i, j, k;
    SET(1);
    int n = 1000000;
    for(i = 2; i < n; i++) {
        if(!GET(i)) {
            p[pt] = i, pt++;
            for(k = n/i, j = i*k; k >= i; k--, j -= i)
                SET(j);
        }
    }
}
int num_reverse(int n) {
    int tmp = 0;
    while(n) {
        tmp = tmp*10 + n%10;
        n /= 10;
    }
    return tmp;
}
int BIT[131072] = {};
int SEG[(131072<<1)+5] = {}, M;
void modify(int idx, int k) {
    while(idx <= 131072) {
        BIT[idx] += k;
        idx += idx&(-idx);
    }
}
int query(int idx) {
    int sum = 0;
    while(idx) {
        sum += BIT[idx];
        idx -= idx&(-idx);
    }
    return sum;
}
int main() {
    sieve();
    int i, j, k;
    int n, m;
    for(i = 0; i < pt; i++) {
        n = num_reverse(p[i]);
        while(n <= 999999)
            n *= 10;
        rp[i] = n;
    }
    sort(rp, rp+pt);
    for(i = 0; i < pt; i++) {
        n = rp[i], m = 0;
        for(j = 0; j < pt && (long long)p[j]*p[j] <= n; j++) {
            if(n%p[j] == 0) {
                while(n%p[j] == 0)
                    n /= p[j], m++;
            }
        }
        if(n != 1)    m++;
        R[rp[i]] = i+1;
        A[i+1] = m;
        modify(i+1, m);
    }
    for(M = 1; M < pt+2; M <<= 1);
    for(i = 2*M-1; i >= 1; i--) {
        if(i >= M)    SEG[i] = 1;
        else        SEG[i] = SEG[i<<1] + SEG[i<<1|1];
    }
    char cmd[5];
    while(scanf("%s %d", cmd, &n) == 2) {
        if(cmd[0] == 'd') {
            int idx = R[n];//i-th
            int s = idx+M-1;
            modify(idx, -A[idx]);
            while(s) {
                SEG[s]--;
                s >>= 1;
            }
        } else {
            int s;
            n++;
            for(s = 1; s < M;) {
                if(SEG[s<<1] < n)
                    n -= SEG[s<<1], s = s<<1|1;
                else
                    s = s<<1;
            }
            int idx = s-M+1;
            printf("%d\n", query(idx));
        }
    }
    return 0;
}