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上方有多少碟并将此碟放到开头 直接想其实就是一线段的区间更新,单点求值,但是根据题意我们可以这样想 首先我们倒着存 ...
随机推荐
- LightOJ 1317 第八次比赛 A 题
Description You probably have played the game "Throwing Balls into the Basket". It is a si ...
- oracle 日志文件管理
OS: [root@b28-122 ~]# more /etc/oracle-releaseOracle Linux Server release 5.7 DB: SQL> select * f ...
- 九度oj 1530 最长不重复子串
原题链接:http://ac.jobdu.com/problem.php?pid=1530 字符串简单题,看似O(n^2)的复杂度10000的数据量会tle,其实最长不重复子串不超过26个嘛... 如 ...
- ios中怎么样点击背景退出键盘
//退出键盘 只需一句,药到病除 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [self.view endEdi ...
- php之常用函数库
1.时间和日期 如何获取时间戳 time()--从1970年开始计算的毫秒数 echo time(); 日期 echo date('Y-m-d H:i:s'); 获取默认是时区 echo date_d ...
- Layout Support 获取上下bar的长度
Layout Support This protocol . You can use layout guides as layout items in the NSLayoutConstraint f ...
- NPOI导出word,以及对table的一些设置
参考网址:http://www.aiuxian.com/article/p-1970779.html NPOI版本:2.1.3.1 最终效果图: 代码: /// <summary> /// ...
- Ubuntu系统安装配置Pintos和Bochs
Ubuntu系统安装配置 Pintos 和 Bochs 安装过程 首先是UEFI启动模式下Win8.1安装Ubuntu14.04双系统,由于篇幅过长,就不在这里详写.可见博主的另一篇博客http:// ...
- [收藏]win8安装弹出输入的产品密钥与用于安装任何可用windows映像都不匹配
问题描述: 帮朋友装win8(第一次装大神不要喷我啊)结果到 现在安装 这一步的时候 点击 现在安装 弹出个窗口 说输入的产品密钥与用于安装任何可用windows映像都不匹配.请输入其他产品密钥 解决 ...
- Daily Scrum5
总体来说,我们今天的工作遇到了一些阻碍.前期的对于代码的大量阅读并没有使我们的进度突飞猛进.今天我们完成了关于敏感词汇辨别优化和防滥用部分的代码(之后会有微博来详细介绍),但是我们无法运行程序并测试, ...