hdu 5726 GCD (二分+ST表)★

来源:互联网 发布:淘宝买家问质量怎么样 编辑:程序博客网 时间:2024/05/20 06:08

题目大概说给一个包含n个数的序列,多次询问有多少个区间GCD值等于某个区间的gcd值。

 

任何一个区间不同的GCD个数是log级别的,因为随着右端点向右延伸GCD是单调不增的,而每次递减GCD至少除以2。

考虑固定左端点,最多就nlogn种GCD,可以直接把所有区间GCD值预处理出来,用map存储各种GCD值的个数,查询时直接输出。

具体是这样处理的:枚举左端点,进行若干次二分查找,看当前GCD值最多能延伸到哪儿,进而统计当前GCD值的数量。

而求区间GCD,用ST表,预处理一下,就能在O(1)时间复杂度求出任意区间的gcd了。


#include <set>#include <map>#include <stack>#include <queue>#include <deque>#include <cmath>#include <vector>#include <string>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define L(i) i<<1#define R(i) i<<1|1#define INF  0x3f3f3f3f#define pi acos(-1.0)#define eps 1e-9#define maxn 10010#define MOD 1000000007int gcd(int a,int b){    while(b)    {        int t = b;        b = a % b;        a = t;    }    return a;}int n,st[110010][17];void init(){    for(int j = 1; j < 17; j++)        for(int i = n; i >= 1; i--)        {            if(i+(1<<j)-1 > n)                continue;            st[i][j] = gcd(st[i][j-1],st[i+(1<<j-1)][j-1]);        }}int logs[100100];int query(int a,int b){    int k = logs[b-a+1];    return gcd(st[a][k],st[b-(1<<k)+1][k]);}int main(){    int t,C = 1;    scanf("%d",&t);    for(int i = 1; i < 100100; i++)        logs[i] = log2(i) + 1e-6;    while(t--)    {        scanf("%d",&n);        for(int i = 1; i <= n; i++)            scanf("%d",&st[i][0]);        init();        map<int,long long> ret;        for(int i = 1; i <= n; i++)        {            int g = st[i][0];            int j = i;            while(j <= n)            {                int l = j, r = n;                while(l < r)                {                    int mid = l + r + 1 >> 1;                    if(query(i,mid) == g)                        l = mid;                    else                        r = mid - 1;                }                ret[g] += (l - j + 1);                j = l + 1;                g = query(i,j);            }        }        printf("Case #%d:\n",C++);        int q,a,b;        scanf("%d",&q);        while(q--)        {            scanf("%d%d",&a,&b);            int g = query(a,b);            printf("%d %lld\n",g,ret[g]);        }    }    return 0;}


0 0