hdu4777 求区间内与其它数均互质的数的个数(树状数组+离线处理)
来源:互联网 发布:永泰县财政局网络 编辑:程序博客网 时间:2024/05/21 12:48
hdu4777 求区间内与其它数均互质的数的个数
题意:有n(1<=n<=200000)个数字,m(1<=m<=200000)个查询,每次询问[l,r]区间这些数字中,和区间内其他数都互质的数有多少个。
解题思路:
离线处理+树状数组,首先预处理出[1,200000]所有数的质因子,放到have[]里面,然后根据输入的n个数w[],求出每个数的它的质因子
出现的最左位置以及最右位置。然后对m个查询离线,按右边由小到大排序。如第二个样例:
3 6 1 2 5 3
l[] 0 1 0 2 0 2
r[] 2 4 7 7 7 7
V[] {} {1} {} {2} {3,4,5,6}
明显,求[left,right]区间的结果是(right-left+1-notFit),其中notFit=i的数量(l[i]>=left)+i的数量(r[i]<=right)-i的数量(l[i]>=left && r[i]<=right) ;
可以从左往右扫描,对于第i个,先add(l[i],1),因为左边的notFit数目多了1(自己),然后对V[i]集合里的数x=V[i][j],先add(x,1);因为
x的右边已经超出范围了,所以变为notFit,另外要add(l[x],-1);意思是减去右边notFit的并且左边也notFit的,所以结果就是
题意:有n(1<=n<=200000)个数字,m(1<=m<=200000)个查询,每次询问[l,r]区间这些数字中,和区间内其他数都互质的数有多少个。
解题思路:
离线处理+树状数组,首先预处理出[1,200000]所有数的质因子,放到have[]里面,然后根据输入的n个数w[],求出每个数的它的质因子
出现的最左位置以及最右位置。然后对m个查询离线,按右边由小到大排序。如第二个样例:
3 6 1 2 5 3
l[] 0 1 0 2 0 2
r[] 2 4 7 7 7 7
V[] {} {1} {} {2} {3,4,5,6}
明显,求[left,right]区间的结果是(right-left+1-notFit),其中notFit=i的数量(l[i]>=left)+i的数量(r[i]<=right)-i的数量(l[i]>=left && r[i]<=right) ;
可以从左往右扫描,对于第i个,先add(l[i],1),因为左边的notFit数目多了1(自己),然后对V[i]集合里的数x=V[i][j],先add(x,1);因为
x的右边已经超出范围了,所以变为notFit,另外要add(l[x],-1);意思是减去右边notFit的并且左边也notFit的,所以结果就是
sum( right-left+1-( sum(right)-sum(left-1) ) )
参考资料:http://blog.csdn.net/ok_again/article/details/15235883
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<math.h>#include<iostream>#include<algorithm>#include<queue>#include<stack>#include<vector>#include<map>#include<set>#include<deque>#include<bitset>#define N 201005using namespace std;int w[N],l[N],r[N];//l[i],r[i]保存第i个数的质因子出现的最左位置以及最右位置vector<int>V[N];//V[i]存储的是j,其中r[j]=ivector<int>have[N],VPrime;//have[i]存储的是数字i分解的质因子,VPrime存储的是[1,200000]的素数int ans[N];//存储结果int flag[N];struct node{ int left,right,id;}p[N];int cmp(node aa,node bb){ return aa.right<bb.right;}int ar[N];int lowb(int t){ return t&(-t);}void add(int i,int v){ if(i==0) return; for(;i<N;ar[i]+=v,i+=lowb(i));}int sum(int i){ int s=0; for(;i>0;s+=ar[i],i-=lowb(i)); return s;}void getHave(int index,int v){ int i=0; while(v>1&&i<VPrime.size()) { if(VPrime[i]*VPrime[i]>v) { have[index].push_back(v); break; } if(i<VPrime.size()&& v%VPrime[i]==0) { have[index].push_back(VPrime[i]); } while(i<VPrime.size()&& v%VPrime[i]==0) { v/=VPrime[i]; } i++; }}bool prime[N];void init(){ int i,j; memset(prime,0,sizeof(prime)); prime[1]=prime[0]=1; for(i=2;i<=N-2;i++) for(j=2;i*j<=N-2;j++) { prime[i*j]=1; } VPrime.clear(); for(i=2;i<=N-2;i++) { if(prime[i]==0) VPrime.push_back(i); } for(i=0;i<N;i++) { have[i].clear(); } for(i=2;i<N;i++) { getHave(i,i); }}void init2(int n)//计算出l数组,r数组以及V[]{ for(int i=0;i<=n;i++) { V[i].clear(); } memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(flag,0,sizeof(flag)); for(int i=1;i<=n;i++) { int left=0; for(int j=0;j<have[w[i]].size();j++) { left=max(left,flag[have[w[i]][j]]); } l[i]=left; for(int j=0;j<have[w[i]].size();j++) { flag[have[w[i]][j]]=i; } } for(int i=1;i<N;i++)//这里要初始化为n+1 {flag[i]=n+1;} for(int i=n;i>=1;i--) { int right=n+1; for(int j=0;j<have[w[i]].size();j++) { right=min(right,flag[have[w[i]][j]]); } r[i]=right; for(int j=0;j<have[w[i]].size();j++) { flag[have[w[i]][j]]=i; } } for(int i=1;i<=n;i++) { V[r[i]].push_back(i); }}int main(){ int i,j,k; int n,m,t; init(); while(scanf("%d%d",&n,&m)!=EOF&&!(n==0&&m==0)) { for(i=1;i<=n;i++) { scanf("%d",&w[i]); } init2(n); for(i=1;i<=m;i++) { scanf("%d%d",&p[i].left,&p[i].right); p[i].id=i; } sort(p+1,p+1+m,cmp); memset(ar,0,sizeof(ar)); i=1; for(j=1;j<=m;j++) { while(i<=p[j].right) { add(l[i],1);//将左边notFit的+1 for(k=0;k<V[i].size();k++) { add(l[V[i][k]],-1);//将左边跟右边同时notFit的-1,去掉重复 add(V[i][k],1);//将右边notFit的+1 } i++; } int notFit=sum(p[j].right)-sum(p[j].left-1); ans[p[j].id]=p[j].right-p[j].left+1-notFit; } for(i=1;i<=m;i++) { printf("%d\n",ans[i]); } }}/*input:3 22 1 41 21 36 43 6 1 2 5 31 34 64 42 60 0output:211312*/
0 0
- hdu4777 求区间内与其它数均互质的数的个数(树状数组+离线处理)
- hdu4777 Rabbit Kingdom 离线树状数组 求询问区间内的区间数
- HDU 4777 树状数组求区间内 与该区间都互质的数个数
- hdu4417 树状数组(求指定区间比指定数小的数的个数)
- hdu 5869 区间内不同的GCD数(离线+树状数组)
- 线段树离线处理(区间内不同的数的个数)hdu3333
- BZOJ 题目1878: [SDOI2009]HH的项链(树状数组离线求区间不同种类数)
- SPOJ DQUERY(树状数组离线处理 or 主席树 区间不同数个数)
- 求任意区间里比x小的数的个数(树状数组)
- SPOJ D-query 区间不同数的个数 [在线主席树 or 离线树状数组]
- poj 2299 Ultra-QuickSort(利用树状数组变形,求一个数左边比它大的数的个数)
- Codeforces 703D Mishka and Interesting sum (树状数组求区间内不同的数的异或和)
- 区间内有多少个不同的数字(离线树状数组)
- 【HDU 3333】【离线询问 树状数组 前驱思想】Turing Tree【 求区间中不同的数的和】
- SPOJ3267 D-Query 树状数组离线操作 或 主席树 查询某一区间内有多少不同的数
- hdu3709(求区间内平衡数的个数)数位dp
- HDU 5869 求区间中不同连续序列的gcd的个数(树状数组)
- 树状数组—求逆序数的个数
- 植物大战僵尸做挂教程。(共7集)最详细!!!!适合学习!!!
- ubuntu下怎么通过命令行打开各种类型的文件
- 64位的win7系统安装mysql步骤
- 一道01背包问题(动态规划)
- 如何设置java drawLine画的线的粗细
- hdu4777 求区间内与其它数均互质的数的个数(树状数组+离线处理)
- Oracle Package中的包变量的使用
- 开放源码的微微信.NET 0.8 版发布了
- Magento技术架构简介
- ibatis 入门
- WinExec、ShellExecute和CreateProcess及返回值判断方式
- 使用 GIT 获得Linux Kernel的代码并查看,追踪历史记录
- cocos2d+TexturePackerGUI动画制作
- git_基本使用操作,绝对最清楚