HDU 5726 GCD 2016年多校D题

题意:给你一个长度为n 的数组,q次询问,每次询问给一个区间 l,r 问原数组有多少个连续的区间的GCD与该区间的GCD 相等。

思路:用MAP记录所有区间的各种GCD值的数量。

代码如下:(不要全部用LL,要T呀大哭

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
#include<vector>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<algorithm>
#include<complex>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define nn 100100
#define maxk 18
#define LL long long
#define Uint unsiged long long
#define mod 1000000007
#define inf 0xffffff
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1

struct FastIO {
    static const int S = 1310720;
    int wpos; char wbuf[S];
    FastIO() : wpos(0) {}
    inline int xchar() {
        static char buf[S];
        static int len = 0, pos = 0;
        if (pos == len)
            pos = 0, len = fread(buf, 1, S, stdin);
        if (pos == len) return -1;
        return buf[pos ++];
    }
    inline int xuint() {
        int c = xchar(), x = 0;
        while (c <= 32) c = xchar();
        for (;'0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
        return x;
    }
    inline int xint() {
        int s = 1, c = xchar(), x = 0;
        while (c <= 32) c = xchar();
        if (c == '-') s = -1, c = xchar();
        for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
        return x * s;
    }
    inline void xstring(char *s) {
        int c = xchar();
        while (c <= 32) c = xchar();
        for(; c > 32; c = xchar()) *s++ = c;
        *s = 0;
    }
    inline void wchar(int x) {
        if (wpos == S) fwrite(wbuf, 1, S, stdout), wpos = 0;
        wbuf[wpos ++] = x;
    }
    inline void wint(int x) {
        if (x < 0) wchar('-'), x = -x;
        char s[24];
        int n = 0;
        while (x || !n) s[n ++] = '0' + x % 10, x /= 10;
        while (n--) wchar(s[n]);
    }
    inline void wstring(const char *s) {
        while (*s) wchar(*s++);
    }
    ~FastIO() {
        if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
    }
}io;

int a[nn],n;
int tg[nn<<2];
int get_gcd(int x,int y)
{
    return y==0?x:get_gcd(y,x%y);
}

inline void pushup(int rt)
{
    tg[rt]=get_gcd(tg[rt<<1],tg[rt<<1|1]);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        tg[rt]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
int query(int l,int r,int rt,int ll,int rr)
{
    if(ll<=l && r<=rr)
        return tg[rt];
    int mid=(l+r)>>1;
    if(rr<=mid) return query(lson,ll,rr);
    else if(ll>mid) return query(rson,ll,rr);
    else return get_gcd(query(lson,ll,rr),query(rson,ll,rr));
}
int main()
{
    int m,t;
    t=io.xint();
    for(int tt=1;tt<=t;tt++)
    {
        n=io.xint();
        for(int i=1;i<=n;i++)
            a[i]=io.xint();
        map<int,LL>mp;
        build(1,n,1);
        for(int i=1;i<=n;i++)
        {
            int val=a[i];
            int sl=i,sr=n,l=i,r=n;
            while(val>=1)
            {
                l=sl;r=sr;
                if(val==1)
                {
                    mp[1]+=(LL)(n-l+1);
                    break;
                }
                while(l<r)
                {
                    int mid=(l+r)>>1;
                    int tmp=query(1,n,1,i,mid);
                    if(tmp<val) r=mid-1;
                    else
                    {
                        l=mid;
                        if(l+1==r)
                        {
                            int val1=query(1,n,1,i,l);
                            int val2=query(1,n,1,i,r);
                            if(val1==val2) l=r;
                            break;
                        }
                    }
                }
                mp[val]+=(LL)(l-sl+1);
                sl=l+1;
                sr=n;
                if(sl<=n) val=query(1,n,1,i,sl);
                else break;
            }
        }
        printf("Case #%d:\n",tt);
        m=io.xint();
        while(m--)
        {
            int x,y;
            x=io.xint();
            y=io.xint();
            int ans=query(1,n,1,x,y);
            printf("%d %lld\n",ans,mp[ans]);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值