HDOJ5726解题报告【ST表】

题目地址:

  http://acm.hdu.edu.cn/showproblem.php?pid=5726

题目概述:

  给出n个数以及q个询问,每个询问有两个数l,r,求[l,r]区间的gcd以及区间gcd等于这个gcd的所有方案数。

大致思路:

  乍一看线段树,但是这个题询问太多了,所以我们使用ST表来做这个题目。

  区间max,min,gcd,lcm都可以用ST表来做,ST表在O(nlogn)的预处理之后,对每个询问的时间是O(1)的。

  而对于方案数,根据gcd不增的性质,我们可以枚举左端点,二分右端点,预处理所有的gcd对应的方案数。

复杂度分析:

  ST表的处理是O(nlogn),方案数的预处理也是O(nlogn),而对于每个询问复杂度是O(1)。总的时间复杂度为O(T*nlogn)。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <ctime>
#include <map>
#include <stack>
#include <set>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;

#define sacnf scanf
#define scnaf scanf
#define maxn 100010
#define maxm 18
#define inf 1061109567
#define Eps 0.000001
const double PI=acos(-1.0);
#define mod 1000000007
#define MAXNUM 10000
#define For(i,j,k) for(int (i)=(j);(i)<=(k);(i)++)
#define mes(a,b) memset((a),(b),sizeof(a))
typedef long long ll;
typedef unsigned long long ulld;
void Swap(int &a,int &b) {int t=a;a=b;b=t;}
ll Abs(ll x) {return (x<0)?-x:x;}

int st[maxn][maxm],n,mk;
map<int,ll> q;

int gcd(int a,int b)
{
    if(a<b) swap(a,b);
    return b?gcd(b,a%b):a;
}

int query(int l,int r)
{
    int k=(int)log2((double)(r-l+1));
    return gcd(st[l][k],st[r-(1<<k)+1][k]);
}

void build_q()
{
    for(int i=1;i<=n;i++)
    {
        int j=i,temp=st[i][0];
        while(j<=n)
        {
            int l=j,r=n;
            while(l<r)
            {
                int m=(l+r+1)>>1;
                if(query(l,m)==temp) l=m;
                else r=m-1;
            }
            q[temp]+=(l-j+1);
            j=l+1;temp=query(i,j);
        }
    }
}

int main()
{
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    //clock_t st=clock();
    int T;scanf("%d",&T);
    For(kase,1,T)
    {
        printf("Case #%d:\n",kase);mes(st,0);
        scanf("%d",&n);
        For(i,1,n) scanf("%d",&st[i][0]);
        for(int k=1;(1<<k)<=n;k++)
            For(i,1,n-(1<<k)+1) st[i][k]=gcd(st[i][k-1],st[i+(1<<(k-1))][k-1]);
        q.clear();build_q();
        int m,l,r;scanf("%d",&m);
        while(m--)
        {
            scanf("%d%d",&l,&r);
            int ans=query(l,r);
            printf("%d %I64d\n",ans,q[ans]);
        }
    }
    //clock_t ed=clock();
    //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC);
    return 0;
}

 

posted @ 2017-07-08 18:51  CtrlKismet  阅读(200)  评论(0编辑  收藏  举报