UVA 11610 Reverse Prime (数论+树状数组+二分,难题)
参考链接
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 (数论+树状数组+二分,难题)的更多相关文章
- UVA 10909 Lucky Number(树状数组+二分+YY)
此题测试时预处理等了很久,结果470ms过了...... 题意:开始不怎么懂,结果发现是这个: 波兰裔美国数学家斯塔尼斯拉夫·乌拉姆(Stanislaw Ulam)在20世纪50年代中期开发出了另一种 ...
- POJ 2828 Buy Tickets (线段树 or 树状数组+二分)
题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容 ...
- TZOJ 4602 高桥和低桥(二分或树状数组+二分)
描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算“淹了两次”.举 ...
- POJ 2182 Lost Cows 【树状数组+二分】
题目链接:http://poj.org/problem?id=2182 Lost Cows Time Limit: 1000MS Memory Limit: 65536K Total Submis ...
- 树状数组+二分||线段树 HDOJ 5493 Queue
题目传送门 题意:已知每个人的独一无二的身高以及排在他前面或者后面比他高的人数,问身高字典序最小的排法 分析:首先对身高从矮到高排序,那么可以知道每个人有多少人的身高比他高,那么取较小值(k[i], ...
- P2161 [SHOI2009]会场预约[线段树/树状数组+二分/STL]
题目描述 PP大厦有一间空的礼堂,可以为企业或者单位提供会议场地.这些会议中的大多数都需要连续几天的时间(个别的可能只需要一天),不过场地只有一个,所以不同的会议的时间申请不能够冲突.也就是说,前一个 ...
- The Stream of Corning 2( 权值线段树/(树状数组+二分) )
题意: 有两种操作:1.在[l,r]上插入一条值为val的线段 2.问p位置上值第k小的线段的值(是否存在) 特别的,询问的时候l和p合起来是一个递增序列 1<=l,r<=1e9:1< ...
- 牛客多校第3场 J 思维+树状数组+二分
牛客多校第3场 J 思维+树状数组+二分 传送门:https://ac.nowcoder.com/acm/contest/883/J 题意: 给你q个询问,和一个队列容量f 询问有两种操作: 0.访问 ...
- UVA 1513 Movie collection (树状数组+反向存储)
题意:给你n盘歌碟按照(1....n)从上到下放,接着m个询问,每一次拿出x碟,输出x上方有多少碟并将此碟放到开头 直接想其实就是一线段的区间更新,单点求值,但是根据题意我们可以这样想 首先我们倒着存 ...
随机推荐
- webpack 学习笔记 02 快速入门
webpack 的目标 将依赖项分块,按需加载. 减少web app的初始加载时间. 使每一个静态集合都能够作为组件使用. 有能力集成第三方库,作为组件使用. 高度可配置化. 适用于大型项目. INS ...
- 基于socket的客户端和服务端聊天机器人
服务端代码如下: using System;using System.Net;using System.Net.Sockets;using System.Text;using System.Threa ...
- hdu 1316 How Many Fibs?
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1316 How Many Fibs? Description Recall the definition ...
- CPU制造工艺 级选来决定cpu等级
CPU制造工艺 编辑 CPU制造工艺又叫做CPU制程,它的先进与否决定了CPU的性能优劣.CPU的制造是一项极为复杂的过程,当今世上只有少数几家厂商具备研发和生产CPU的能力.CPU的发展史也可以看作 ...
- Swift :?和 !
Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值, 也就是说变量不会有默认值,所以要求使用变量之前必须要对其初始化 .如果在使用变量之前不进行初始化就会报错: v ...
- 修改一行代码提升 Postgres 性能 100 倍
http://www.datadoghq.com/2013/08/100x-faster-postgres-performance-by-changing-1-line/ SELECT c.key, ...
- LoadRunner - 当DiscuzNT遇上了Loadrunner(下) (转发)
当DiscuzNT遇上了Loadrunner(下) 在之前的两篇文章中,基本上介绍了如何录制脚本和生成并发用户,同时还对测试报告中的几个图表做了简单的说明.今天这篇文章做为这个系列的最后一篇,将会介绍 ...
- android不要标题栏
去除标题栏title其实非常简单,他有两种方法,一种是在代码中添加,另一种是在AndroidManifest.xml中添加: 1.在代码中实现: 在此方法setContentView(R.layout ...
- log4j打印参数
%m 输出代码中指定的消息 %p 输出优先级,即DEBUG,INFO,WARN,ERROR,FATAL %r 输出自应用启动到输出该log信息耗费的毫秒数 %c 输出所属的类目,通 ...
- c++中头文件include规则浅析[译]
英文原文地址 在开发大型的软件项目时,头文件需要得到恰当的管理,甚至在c中也会面临这种问题,当我们用c++开发时,头文件的管理会变得更复杂,更加耗费我们的时间去管理,下面我将讲一些包含规则来简化这个苦 ...