HDU5726 GCD 二分查找加RMQ 多校联赛第一场
2016-07-28 09:22
387 查看
GCD
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 833 Accepted Submission(s): 153
Problem Description
Give you a sequence of N(N≤100,000) integers
: a1,...,an(0<ai≤1000,000,000).
There are Q(Q≤100,000) queries.
For each query l,r you
have to calculate gcd(al,,al+1,...,ar) and
count the number of pairs(l′,r′)(1≤l<r≤N)such
that gcd(al′,al′+1
1ddc4
,...,ar′) equal gcd(al,al+1,...,ar).
Input
The first line of input contains a number T,
which stands for the number of test cases you need to solve.
The first line of each case contains a number N,
denoting the number of integers.
The second line contains N integers, a1,...,an(0<ai≤1000,000,000).
The third line contains a number Q,
denoting the number of queries.
For the next Q lines,
i-th line contains two number , stand for the li,ri,
stand for the i-th queries.
Output
For each case, you need to output “Case #:t” at the beginning.(with quotes, t means
the number of the test case, begin from 1).
For each query, you need to output the two numbers in a line. The first number stands for gcd(al,al+1,...,ar) and
the second number stands for the number of pairs(l′,r′) such
that gcd(al′,al′+1,...,ar′) equal gcd(al,al+1,...,ar).
Sample Input
1
5
1 2 4 6 7
4
1 5
2 4
3 4
4 4
Sample Output
Case #1:
1 8
2 4
2 4
6 1
Statistic | Submit | Clarifications | Back
题解
关于MRQ可以 http://blog.csdn.net/hyyjiushiliangxing/article/details/52045507
思路:首先要知道的是不同区间的GCD会随着右端点延伸GCD是单调不增的,那么考虑枚举左端点,然后二分当前GCD看看最多能延伸到哪里,然后统计当前GCD数量,可以先把所有区间GCD预处理出来然后用map存,因为公因子不会太多
我们注意观察gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar),当l固定不动的时候,r=l...nr=l...n时,我们可以容易的发现,随着rr的増大,gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar)是递减的,同时gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar)最多
有log\
1000,000,000log 1000,000,000个不同的值,为什么呢?因为a_{l}al最多也就有log\
1000,000,000log 1000,000,000个质因数
所以我们可以在log级别的时间处理出所有的以L开头的左区间的gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar) 那么我们就可以在n\
log\ 1000,000,000n log 1000,000,000的时间内预处理出所有的gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar)然后我们可以用一个map来记录,gcd值为key的有多少个
然后我们就可以对于每个询问只需要查询对应gcd(a_{l},a_{l+1},...,a_{r})gcd(al,al+1,...,ar)为多少,然后再在map
里面查找对应答案即可.
#include<bits/stdc++.h> using namespace std; const int maxn=100000+500; #define LL long long int gcd(int a,int b)//求两个数的最大公约数 { return b?gcd(b,a%b):a; } int dgcd[maxn][20]; int d[maxn];//存放ai map<int ,LL>ans;//建立map容器,查找相同的最大公约数 int res[maxn]; void init(int n,int d[])//用RMQ打表 { for(int i=1; i<=n; i++) { dgcd[i][0]=d[i]; } for(int j=1; (1<<j)<=n; j++) { for(int i=1; i+(1<<j)-1<=n; i++) { dgcd[i][j]=gcd(dgcd[i][j-1],dgcd[i+(1<<(j-1))][j-1]); } } } int getgcd(int L,int R) { int k=0; while((1<<(k+1))<=R-L+1) k++; return gcd(dgcd[L][k],dgcd[R-(1<<k)+1][k]); } int main() { int t,cas=1; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); for(int i=1; i<=n; i++) scanf("%d",&d[i]); init(n,d); int q; scanf("%d",&q); for(int i=1; i<=q; i++) { int L,R; scanf("%d%d",&L,&R); res[i]=getgcd(L,R);//求出这两数的最大公约数 ans[res[i]]=0;//把最大公约数放进map容器中 } for(int i=1; i<=n; i++)//二分查找 { int np=i; while(np<=n) { int num=getgcd(i,np); int l=np,r=n; int cnt=0; while(l<=r) { int mid=(l+r)/2; if(getgcd(i,mid)==num) { l=mid+1; cnt=mid; } if(getgcd(i,mid)<num) { r=mid-1; } else l=mid+1,cnt=mid; } ans[num]+=cnt-np+1; np=r+1; } } printf("Case #%d:\n",cas++); for(int i=1; i<=q; i++) { printf("%d %lld\n",res[i],ans[res[i]]); } } }
相关文章推荐
- C++二分查找在搜索引擎多文档求交的应用分析
- C语言编程中实现二分查找的简单入门实例
- C#二分查找算法实例分析
- 二分查找算法在C/C++程序中的应用示例
- 在MySQL中实现二分查找的详细教程
- Java实现二分查找算法实例分析
- JAVA冒泡排序和二分查找的实现
- Python基于二分查找实现求整数平方根的方法
- python二分查找算法的递归实现方法
- Python二分查找详解
- 简介二分查找算法与相关的Python实现示例
- 详解iOS多线程GCD的使用
- 详解IOS中GCD的使用
- 详解iOS中多线程app开发的GCD队列的使用
- python二分查找算法的递归实现方法
- Python基于二分查找实现求整数平方根的方法
- gcd
- OC多线程
- 多线程应该知道的那几件事 GCD NSThread NSOperation
- 多线程编程4 - GCD