HDU_5729_rmq+二分

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU_5729_rmq+二分相关的知识,希望对你有一定的参考价值。

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

 

rmq修改成gcd的,关键是找个数,用二分来找,刚开始理解了好久,因为每个区间内gcd是递减的,所以可以优化暴力枚举。

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;

int a[100005],n,dp[100005][20];
map<int,long long> mp;
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}

void rmq_init(int len)
{
    for(int i = 1;i <= len;i++)
    {
        dp[i][0] = a[i];
    }

    for(int j = 1;(1<<j) <= len;j++)
    {
        for(int i = 1;i+(1<<j)-1 <= len;i++)
        {
            dp[i][j] = gcd(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
}

int rmq_query(int l,int r)
{
    int k = (int)(log((double)(r-l+1))/log(2.0));
    return gcd(dp[l][k],dp[r-(1<<k)+1][k]);
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int z = 1;z <= T;z++)
    {
        mp.clear();
        printf("Case #%d:\n",z);
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)   scanf("%d",&a[i]);
        rmq_init(n);
        for(int i = 1;i <= n;i++)
        {
            int l = i,r = i;
            while(r <= n)
            {
                int ll = r,rr = n;
                int v = rmq_query(l,r);
                while(ll <= rr)
                {
                    int mid = (ll+rr)/2;
                    if(rmq_query(l,mid) >= v)  ll = mid+1;
                    else    rr = mid-1;
                }
                mp[v] += ll-r;
                r = ll;
            }
        }
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            int ans = rmq_query(l,r);
            printf("%d %lld\n",ans,mp[ans]);
        }
    }
    return 0;
}

 

以上是关于HDU_5729_rmq+二分的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 5289 Assignment (RMQ+二分)

HDU 5289 Assignment(二分+RMQ-ST)

HDU_6194 后缀数组+RMQ

HDU 2199 (二分&三分 _A题)解题报告

HDU_1969_二分

cf689d ST表RMQ+二分