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上方有多少碟并将此碟放到开头 直接想其实就是一线段的区间更新,单点求值,但是根据题意我们可以这样想 首先我们倒着存 ...
随机推荐
- 菜鸟学习Struts——Scope属性
一.概念. 在Action映射配置中,Scope属性可以取值为:request或session.Scope属性表示:Struts框架在将 ActionForm对象(与目标Action匹配的Ac ...
- 动态切换采用 CSplitterWnd 静态划分的视图布局(MFC)
标题读起来有些拗口,具体是什么情况,我们来看: 一.问题的提出 一个采用MFC开发的软件,其窗体视图采用CSplitterWnd三分,效果如下图所示: 图1 软件的默认视图布局 该MFC开发的软件功能 ...
- SQL中的内连接外连接和交叉连接是什么意思?
内连接又分为等值连接.自然连接和不等连接三种. 外连接分为左外连接(LEFT OUTER JOIN或LEFT JOIN).右外连接(RIGHT OUTER JOIN或RIGHT JOIN)和全外连接( ...
- having count group by
select count(*) from (select field2,count(field2) from bsgj.table1 group by field,items_id having(c ...
- flask中文问题
在使用flask时在模板中使用了中文,运行的时候遇到下面的问题: UnicodeDecodeError UnicodeDecodeError: 'utf8' codec can't decode by ...
- trap命令使用
分享一个shell脚本技巧,大家写shell脚本的时候,一般而言仅仅保证功能可用,但程序的鲁棒性却不是太好,不够健壮,多数是脚本处理 一些中断信号导致,应对非预期的系统信号,其实系统自带的trap命令 ...
- IT安全的本质
(1)信任:服务端信任客户端的请求参数. (2)可控:客户端的请求参数可以被控制,任意修改. 服务端信任+客户端可控 =不安全. 服务端信任+客户端不可控=安全. 服务端不信任+客户端可控=安全. 服 ...
- 使用JavaScript+Html创建win8应用(二)
向我们的应用中添加JavaScript 的 Windows 库控件,首先我们接着上一个demo把一个评分控件添加进来 与 HTML 控件不同的是,适用于 JavaScript 的 Windows 库控 ...
- 十个优秀的C语言学习资源推荐
学习C语言,需要一点一滴,沉下心来,找个安静的地方,泡上一杯咖啡,在浓郁的香味中一起品味她.-- Boatman Yang 人们通常认为计算机编程很烦,但是有些人却从中发现了乐趣.每一个程序员不得不跟 ...
- Visual Studio 2013 各版本注册码
Visual Studio Ultimate 2013 KEY(密钥):BWG7X-J98B3-W34RT-33B3R-JVYW9 Visual Studio Premium 2013 KEY(密钥) ...