HDU 5726 GCD

11 篇文章 0 订阅
11 篇文章 0 订阅

Description

Give you a sequence of N(N100,000) integers : a1,...,an(0<ai1000,000,000) . There are Q(Q100,000) queries. For each query l,r you have to calculate gcd(al,,al+1,...,ar) and count the number of pairs (l,r)(1l<rN) such that gcd(al,al+1,...,ar) equal gcd(al,al+1,...,ar) .

Solution

这种类型的题目多校很多,挑道简单的讲讲
首先以 l 为左端点,区间的不同gcd个数不会超过 log(m),(m)
那么我们可以枚举一个 l ,不断然后向右二分,把gcd对应的值存入map,这个过程的复杂度是 (O(lognW)+O(lognlogn)),(Wgcd)
考虑到 gcd 的性质,可以考虑用ST表维护区间 gcd
那么 W 就变成了单个gcd计算的复杂度了。

Code

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;

#define pb push_back
#define ph push
#define fi first
#define se second

inline void Max(int &a,int b){if(a<b)a=b;}
inline void Min(int &a,int b){if(a>b||a==-1)a=b;}
template<class T>void rd(T &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
template<class T>void nt(T x){
    if(!x)return;
    nt(x/10);
    putchar(48+x%10);
}
template<class T>void pt(T x){
    if(!x)putchar('0');
    else nt(x);
}
const int M=1e5+5;
const int S=21;
int A[M],g[M][S],_,txt,q,lg2[M],n;
inline int gcd(int n,int m){return m?gcd(m,n%m):n;}
inline void Init(){
    int Mx=0;
    for(int i=0;1<<i<M;++i)
        lg2[1<<i]=i,Mx=i;
    if(!lg2[M-1])lg2[M-1]=Mx+1;
    for(int i=M-1;i;--i)
        if(!lg2[i])lg2[i]=lg2[i+1];
    lg2[1]=0;
}
inline int query(int l,int r){
    int k=lg2[r-l+2]-1;
    return gcd(g[l][k],g[r-(1<<k)+1][k]);
}
map<int,ll>mp;
inline void pret(){
    for(int i=1;i<=n;++i)
        g[i][0]=A[i];
    for(int j=1;(1<<j)<=n;++j)
        for(int i=1;i+(1<<j)-1<=n;++i){
            g[i][j]=gcd(g[i][j-1],g[i+(1<<j-1)][j-1]);
    }
    for(int s=1;s<=n;++s){//左端点
        for(int w=s;w<=n;){
            int val=query(s,w),ans=n+1;
            for(int mid,l=w,r=n;l<=r;){
                mid=l+r>>1;
                if(query(s,mid)!=val)r=mid-1,ans=mid;
                else l=mid+1;
            }//得到最远的gcd相同的位置+1
            mp[val]+=ans-w;
            w=ans;
        }
    }
}
inline void gao(){
    printf("Case #%d:\n",++txt);
    cin>>n;
    mp.clear();
    for(int i=1;i<=n;++i)rd(A[i]);
    for(cin>>q,pret();q--;){
        int l,r,k;rd(l),rd(r);
        pt(k=query(l,r));
        putchar(' ');
        pt(mp[k]);
        putchar('\n');
    }
}
//#define LOCAL
int main(){
#ifdef LOCAL
    freopen("data.in","r",stdin);
    freopen("check.out","w",stdout);
#endif
    for(cin>>_,Init();_--;)gao();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值