码迷,mamicode.com
首页 > 其他好文 > 详细

HDU_5729_rmq+二分

时间:2016-09-30 02:29:24      阅读:133      评论:0      收藏:0      [点我收藏+]

标签:

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+二分

标签:

原文地址:http://www.cnblogs.com/zhurb/p/5922343.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!