您的位置:首页 > 其它

hdu 5726 GCD (区间RMQ )

2017-10-25 14:41 183 查看
题意:  给你n个数和m个查询,输出区间的gcd的值,和问你还有几个区间的gcd值等于你查询的gcd的值。

思路:和上体一样,首先区间GCD是一个单调递减的区间,我们就可以直接 维护一个区间GCD的值,之后枚举左端点二分去找我们与区间GCD值相同的区间,就好了看代码吧

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <iostream>
const int maxn = 110000;
using namespace std;
long long a[maxn],dp[maxn][20];
int n;
map<int,long long>Map;
long long gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
void init()
{
for(int i = 1 ;i <= n ;i++)
{
dp[i][0] = a[i];
}
for(int j = 1 ; (1<<j)<=n ;j++)
{
for(int i = 1 ; i+(1<<j)-1<=n ;i++)
{
dp[i][j] = gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
}
}
int RMQ(int l,int r)
{
int k = 0 ;
while(1<<(k+1)<=(r-l+1)) k++;
return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
}
int lower_b(int l,int r,int p)
{
int s = r+1;
while(l<r)
{
int mid = (l+r+1)>>1;
// cout<<l<<" "<<r<<endl;
if(RMQ(l,mid)==p)
{
l = mid;
}
else
{
r = mid-1;
}
}
return l;
}
int main()
{
int t;
scanf("%d",&t);
int cnt = 1 ;
while(t--)
{
Map.clear();
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
{
scanf("%lld",&a[i]);
}
init();
int m,l,r,mid;
int p;
for(int i = 1 ; i <= n ; i++)
{
p = dp[i][0]; //枚举左端点
int j = i;
while(j<=n)
{
l = j ,r = n;
l = lower_b(l,r,p); //二分去找和当前gcd值相同的区间的位置,
Map[p]+=l-j+1; //j为区间左端点,l为gcd相同的区间的位置
j = l+1; //开始找到下一个
p = RMQ(i,j);
}

}
scanf("%d",&m);
printf("Case #%d:\n",cnt++);
while(m--)
{
scanf("%d%d",&l,&r);
int ans = RMQ(l,r);
printf("%d %lld\n",ans,Map[ans]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: