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上方有多少碟并将此碟放到开头 直接想其实就是一线段的区间更新,单点求值,但是根据题意我们可以这样想 首先我们倒着存 ...
随机推荐
- C# 自定义集合
自定义类型 public class Product { public int Id { get; set; } // 自增ID public string Name { get; set; } // ...
- C实现辗转相除法求两个数的最大公约数
什么是辗转相除法? 辗转相除法(又名欧几里德算法),它主要用于求两个正整数的最大公约数.是已知的最古老的算法. 用辗转相除法求132和72的最大公约数的步骤: 132 / 72 = 1 ... 60 ...
- .NET开源工作流RoadFlow-流程设计-流程步骤设置-按钮设置
按钮设置是配置当前步骤的处理者可以执行哪些操作,每个按钮都有对应的执行脚本(javascript脚本). 从左边的按钮列表中选择当前步骤需要的按钮. 注意:如果是流程最后一步则要配置完成按钮而不是发送 ...
- SequoiaDB版本升级及导入导出工具说明
升级SequoiaDB数据库指导 SequoiaDB安装路径:SDB_HOME=/opt/sequoiadb 数据存储路径:DATABASE=/ opt/sequoiadb/database 一.导出 ...
- Environment 类
提供有关当前环境和平台的信息以及操作它们的方法. 此类不能被继承. using System; using System.Collections; using System.Collections.G ...
- [原创]PostgreSQL Plus Advanced Server批量创建分区表写入亿级别数据实例
当前情况:大表的数据量已接近2亿条我的解决思路:为它创建n*100个分区表,将各个分区表放在不同的tablespace上这样做的优点:1.首先是对这个级别的数据表的性能会有所提升2.数据管理更科学3. ...
- Android--将字节数转化为B,KB,MB,GB的方法
//将字节数转化为MB private String byteToMB(long size){ long kb = 1024; long mb = kb*1024; long gb = mb*1024 ...
- hdu 5326 Work
题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5326 Work Description It’s an interesting experience ...
- iOS学习之视图控制器
一.自定义视图(label-textField组合视图) 1.自定义视图:系统标准UI之外,自己组合出的新的视图. 2.优点:iOS提供了很多UI组件,借助它们我们可以实现不同的功 ...
- AngularJs学习笔记-AngularJS权威教程学习笔记
AngularJS是什么? AngularJS是一种构建动态Web应用的结构化框架.主要用于构建单页面Web应用, 增加抽象级别,使构建交互式的现代Web应用变得更加简单. AngularJS使开发W ...