参考链接
http://blog.csdn.net/acm_cxlove/article/details/8264290
http://blog.csdn.net/w00w12l/article/details/8212782

题意:
  首先定义了一种叫做Reverse Prime的数:是一个7位数,倒置后是一个<=10^6的素数(如1000070)
  然后要把所有的Reverse Prime求出来,排好序。
  然后题目有2种操作:
  q x :求编号0到编号x的Reverse Prime的质因数个数的和
  d x :从表中删掉x(x是一个Reverse Prime)

思路:
  1.先按照题目要求筛选素数,同时求出每个数的只因数个数,再将小于10^6的素数倒置,转化成Reverse Prime,排序离散化
  2.建立两个树状数组,cnt存储区间内的个数,num存储区间内的质因数个数和。
  3.当执行q x 操作时,二分查找最小的mid值,使得sumcnt(mid)=++x(因为x是从0开始的,所以要+1),然后对num树状数组的1~mid区间求和
  4.当执行d x 操作时,可以用二分查找或者map映射获取x的下标,然后对两个树状数组进行更新即可。

  最后要注意的是,由于Reverse Prime是由10^6以下的素数倒置得到的,那么得到的要求是7位,最后一位一定是0,
  我们可以对每个除以10处理。即不考虑末尾的0,最后求质因数个数的时候记得加上2(最后末尾0的因子2和5)。

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <map> using namespace std;
const int maxn=;
int isprime[maxn]; //标记素数
int factor[maxn]; //factor[i]存储i的质因数个数
int prime[maxn]; //存储素数
int idx; //prime数组的下标
long long cnt[maxn]; //统计区间内reverse prime number的个数
long long num[maxn]; //统计区间内reverse prime number的质因数的个数
map<int,int> m; struct RPrimeNum{
int num;
int factor; //存储质因数的个数
bool operator<(const RPrimeNum tmp)const{
return num<tmp.num;
}
}reverse_prime_num[maxn];
int ridx; //reverse_prime_num数组的下标 int lowbit(int x){
return x&(-x);
}
//对数组cnt的更新操作
void updatecnt(int i,int v){
while(i<=ridx){
cnt[i]+=v;
i+=lowbit(i);
}
}
//对数组cnt的求和操作
long long sumcnt(int i){
long long res=;
while(i){
res+=cnt[i];
i-=lowbit(i);
}
return res;
}
//对数组num的更新操作
void updatenum(int i,int v){
while(i<=ridx){
num[i]+=v;
i+=lowbit(i);
}
}
//对数组num的求和操作
long long sumnum(int i){
long long res=;
while(i){
res+=num[i];
i-=lowbit(i);
}
return res;
} void init(){
memset(isprime,,sizeof(isprime));
memset(factor,,sizeof(factor));
idx=-;
//利用素数筛选法求质因数的个数
//因为所有素数都是6位数,但是题目要求是7位数,可见原数的最低位都为0,可以先不考虑这个0,因此maxn的值为1000001
for(int i=;i<maxn;i++){
if(!isprime[i]){
prime[++idx]=i;
for(int j=i*;j<maxn;j+=i){
isprime[j]=i; //记录它被哪个数所筛
}
}
}
//求一个数的质因数个数
for(int i=;i<maxn;i++){
if(!isprime[i])
factor[i]=;
else
factor[i]=factor[i/isprime[i]]+; //1 即为prime[i]
}
ridx=;
int n,rnum;
for(int i=;i<=idx;i++){
n=prime[i];
rnum=;
while(n){
rnum=rnum*+n%;
n=n/;
}
while(rnum<){
rnum*=;
}
reverse_prime_num[++ridx].num=rnum*;
reverse_prime_num[ridx].factor=factor[rnum]+; //2:最后一位没考虑的0,即2和5两个质因子
}
sort(reverse_prime_num+,reverse_prime_num+ridx+); //额,前面第一个应该+1的,一不小心给漏了 for(int i=;i<=ridx;i++)
m[reverse_prime_num[i].num/]=i; //map映射 memset(num,,sizeof(num));
memset(cnt,,sizeof(cnt));
for(int i=;i<=ridx;i++){
updatenum(i,reverse_prime_num[i].factor);
cnt[i]=lowbit(i); //因为更新的值为1,所以只要直接赋值lowbit(i)即可
}
}
//二分搜索第m个reverse prime对应的下标
int binarySearch1(int m){
int l=,r=ridx,mid;
long long ans;
while(r>=l){
mid=(l+r)>>;
ans=sumcnt(mid);
if(ans==m)
return mid;
if(m<ans)
r=mid-;
else
l=mid+;
}
}
//也可以通过二分搜索reverse prime对应的下标
int binarySearch2(int m){
int l=,r=ridx,mid;
while(r>=l){
mid=(l+r)>>;
if(m==reverse_prime_num[mid].num)
return mid;
if(m<reverse_prime_num[mid].num)
r=mid-;
else
l=mid+;
}
}
int main()
{
char str[];
int v;
init();
while(scanf("%s%d",str,&v)!=EOF){
if(str[]=='q'){
v++;
int u=binarySearch1(v);
printf("%lld\n",sumnum(u));
}
else{
//int u=binarySearch2(v); //二分超找对应的下标
int u=m[v/]; //通过建立map映射获取下标
updatecnt(u,-);
updatenum(u,-reverse_prime_num[u].factor);
}
}
return ;
}

UVA 11610 Reverse Prime (数论+树状数组+二分,难题)的更多相关文章

  1. UVA 10909 Lucky Number(树状数组+二分+YY)

    此题测试时预处理等了很久,结果470ms过了...... 题意:开始不怎么懂,结果发现是这个: 波兰裔美国数学家斯塔尼斯拉夫·乌拉姆(Stanislaw Ulam)在20世纪50年代中期开发出了另一种 ...

  2. POJ 2828 Buy Tickets (线段树 or 树状数组+二分)

    题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容 ...

  3. TZOJ 4602 高桥和低桥(二分或树状数组+二分)

    描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算“淹了两次”.举 ...

  4. POJ 2182 Lost Cows 【树状数组+二分】

    题目链接:http://poj.org/problem?id=2182 Lost Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submis ...

  5. 树状数组+二分||线段树 HDOJ 5493 Queue

    题目传送门 题意:已知每个人的独一无二的身高以及排在他前面或者后面比他高的人数,问身高字典序最小的排法 分析:首先对身高从矮到高排序,那么可以知道每个人有多少人的身高比他高,那么取较小值(k[i], ...

  6. P2161 [SHOI2009]会场预约[线段树/树状数组+二分/STL]

    题目描述 PP大厦有一间空的礼堂,可以为企业或者单位提供会议场地.这些会议中的大多数都需要连续几天的时间(个别的可能只需要一天),不过场地只有一个,所以不同的会议的时间申请不能够冲突.也就是说,前一个 ...

  7. The Stream of Corning 2( 权值线段树/(树状数组+二分) )

    题意: 有两种操作:1.在[l,r]上插入一条值为val的线段 2.问p位置上值第k小的线段的值(是否存在) 特别的,询问的时候l和p合起来是一个递增序列 1<=l,r<=1e9:1< ...

  8. 牛客多校第3场 J 思维+树状数组+二分

    牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...

  9. UVA 1513 Movie collection (树状数组+反向存储)

    题意:给你n盘歌碟按照(1....n)从上到下放,接着m个询问,每一次拿出x碟,输出x上方有多少碟并将此碟放到开头 直接想其实就是一线段的区间更新,单点求值,但是根据题意我们可以这样想 首先我们倒着存 ...

随机推荐

  1. 【转】Git常用命令备忘

    Git配置 git config --global user.name "robbin" git config --global user.email "fankai@g ...

  2. CSS3设置字体

    @font-face{ font-family: myFirstFont;src: url('Sansation_Light.ttf')   ,url('Sansation_Light.eot'); ...

  3. ios 中使用SBJson拼接和解析json

    1.ios解析json 使用开源json包,项目地址:      http://stig.github.com/json-framework/ NSData * responseData = [res ...

  4. 关于自定义的NavigationBar

    系统的NavigationBar局限太大,而且现在我要做的navigationBar需要四个按钮,一个Label,一个ImageView,所以不能用系统默认的. 刚刚咨询了一个高手,她的建议是,将系统 ...

  5. vs2010 开发过程中调试时 有错误不中断

    出现这个的原因是调试的设置有问题,修改下设置就好了. 修改方法:点击上边工具栏中   调试--异常 出现以下页面,把引发那列复选框全部勾上,点击确定就好了.

  6. MVC Razor模板引擎输出HTML或者生产HTML文件

    以前做CMS的时候都会根据模板来生成输出HTML或者生成HTML文件. 常用的引擎有VTemplate.NVelocity等等,这个我就布做介绍了. 这里我想说的是.当mvc出现Razor模板引擎的时 ...

  7. python pandas/numpy

    import pandas as pdpd.merge(dataframe1,dataframe2,on='common_field',how='outer') replace NaN datafra ...

  8. P1951: [Sdoi2010]古代猪文

    呜啊啊啊啊,选错了题,原以为很简单的优化+剪枝就能过结果牵扯到了一堆数论知识.我的错,贴上我的代码(已经尽量优化了) ; var n,g,i,j,ans:longint; tem:int64; fun ...

  9. 关于spring mvc MaxUploadSizeExceededException 死循环解决方案

    当看到这文章的时候相信你现在应该遇到这样的问题了,我也是自己遇到了后来找到解决方案了记录下来,如果下次遇到就可以直接解决了. 至于为什么会出现这样的情况,可以看这篇文章:https://bz.apac ...

  10. 快速排序QuickSort

    前几天实现了直接插入排序.冒泡排序和直接选择排序这三个基础排序.今天看了一下冒泡排序的改进算法,快速排序.单独记录一下,后面还有归并和基数排序等 快速排序 1.选择一个支点默认为数组第一个元素及arr ...