您的位置:首页 > 其它

HDU5726

2016-07-27 08:46 387 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5726

ST预处理区间GCD,由唯一分解定理可知,任意起点开始的区间GCD值最多只有logN个,所以可以枚举起点,依靠ST二分求gcd变化的位置求出某起点开始的区间GCD为某值的区间个数,然后用map映射。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<map>
using namespace std;
const int N = 1e5+3;

int G
[31];
int arr
,n;
map<int, long long > mp;

int gcd(int x,int y)
{
int t;
while (y)
{
t = x;
x = y;
y = t%y;
}
return x;
}

void init_st()
{
for (int i=1;i<=n;i++)
{
G[i][0] = arr[i];
}
for (int j=1;j<=30;j++)
{
for (int i=1;i<=n;i++)
{
if (i+(1<<j)-1 <= n)
{
G[i][j] = gcd(G[i][j-1],G[i+(1<<(j-1) ) ][j-1] );
}
}
}
}

int getgcd(int l,int r)
{
int k = (int) (log(r-l+1) / log(2.0) );
int t1 = G[l][k];
int t2 = G[r-(1<<k)+1][k];
return gcd(t1,t2);
}

int main()
{
int T;
scanf("%d",&T);
for (int cnt=1;cnt<=T;cnt++)
{
mp.clear();
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&arr[i]);
}
init_st();

for (int i=1;i<=n;i++)
{
int g = arr[i],j = i;
while (j<=n)
{
int l = j , r = n;
while (l<r)
{
int mid = l+r+1>>1;
if (getgcd(i,mid)==g) l = mid;
else r = mid - 1;
}
mp[g] += (l - j + 1);
j = l + 1;
g = getgcd(i,j);
}
}

int k;
scanf("%d",&k);
printf("Case #%d:\n",cnt);
while (k--)
{
int s,e;
scanf("%d %d",&s,&e);
int t = getgcd(s,e);
printf("%d %I64d\n",t,mp[t]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: