您的位置:首页 > 其它

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(a​l​​,a​l+1​​,...,a​r​​),当l固定不动的时候,r=l...nr=l...n时,我们可以容易的发现,随着rr的増大,gcd(a_{l},a_{l+1},...,a_{r})gcd(a​l​​,a​l+1​​,...,a​r​​)是递减的,同时gcd(a_{l},a_{l+1},...,a_{r})gcd(a​l​​,a​l+1​​,...,a​r​​)最多
有log\
1000,000,000log 1000,000,000个不同的值,为什么呢?因为a_{l}a​l​​最多也就有log\
1000,000,000log 1000,000,000个质因数

所以我们可以在log级别的时间处理出所有的以L开头的左区间的gcd(a_{l},a_{l+1},...,a_{r})gcd(a​l​​,a​l+1​​,...,a​r​​) 那么我们就可以在n\
log\ 1000,000,000n log 1000,000,000的时间内预处理出所有的gcd(a_{l},a_{l+1},...,a_{r})gcd(a​l​​,a​l+1​​,...,a​r​​)然后我们可以用一个map来记录,gcd值为key的有多少个
然后我们就可以对于每个询问只需要查询对应gcd(a_{l},a_{l+1},...,a_{r})gcd(a​l​​,a​l+1​​,...,a​r​​)为多少,然后再在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]]);

}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分查找 gcd RMQ