zoukankan      html  css  js  c++  java
  • Codeforces 475D CGCDSSQ(分治)

    题意:给你一个序列a[i],对于每个询问xi,求出有多少个(l,r)对使得gcd(al,al+1...ar)=xi.

    表面上是询问,其实只要处理出每个可能的gcd有多少个就好了,当左端点固定的时候,随着右端点的移动,gcd必然是单调非增的,而且个数不会超过log(a[i])个,所以总的不同的个数的上界是nlog(ai),所以求出所有是可行的。

    一个分治的做法是这样的,对于一个区间[l,r],分治成[l,mid],[mid+1,r]求解,然后就是合并,合并的时候首先求以[l,mid]右端点为结束点的gcd,然后是[mid+1,r]的左端点为起始点的gcd,两边for一遍,由于不同的gcd最多只有log(ai)个,所以合并的时候就是log(ai)^2。

    所以复杂度大致是这样的 T(n)=2*T(n/2)+log(ai)^2+O(n)  所以大致可以看成是T(n)=2*T(n/2)+O(n),所以复杂度大致就是nlogn的级别的。

    #include <iostream>
    #include <cstring>
    #include <string>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <algorithm>
    #include <map>
    #include <cmath>
    using namespace std;
    
    #define maxn 110000
    #define ll long long
    #define MP make_pair
    
    int n;
    int a[maxn];
    map<int,ll> m;
    
    int gcd(int a,int b){
        return a&&b? gcd(b,a%b):a+b;
    }
    
    void solve(int l,int r)
    {
        if(r-l<=3){
            for(int i=l;i<=r;++i){
                int g=a[i];
                for(int j=i;j<=r;++j){
                    g=gcd(g,a[j]);
                    m[g]++;
                }
            }
            return;
    
        }
        int mid=(l+r)>>1;
        solve(l,mid);
        solve(mid+1,r);
        vector<pair<int,ll> > ls;
        vector<pair<int,ll> > rs;
    
        int cur=-1;
        ll cnt=0;
        int g=a[mid];
        for(int i=mid;i>=l;--i){
            g=gcd(g,a[i]);
            if(g!=cur) {
                if(cur!=-1) ls.push_back(MP(cur,cnt));
                cur=g;cnt=1;
            }
            else{
                ++cnt;
            }
        }
        ls.push_back(MP(cur,cnt));
    
        cur=-1;cnt=0;g=a[mid+1];
        for(int i=mid+1;i<=r;++i){
            g=gcd(g,a[i]);
            if(g!=cur) {
                if(cur!=-1) rs.push_back(MP(cur,cnt));
                cur=g;cnt=1;
            }
            else{
                ++cnt;
            }
        }
        rs.push_back(MP(cur,cnt));
    
        for(int i=0;i<ls.size();++i){
            for(int j=0;j<rs.size();++j){
                int g=gcd(ls[i].first,rs[j].first);
                ll num=ls[i].second*rs[j].second;
                m[g]+=num;
            }
        }
    }
    
    int main()
    {
        while(~scanf("%d",&n)){
            for(int i=1;i<=n;++i){
                scanf("%d",a+i);
            }
            m.clear();
            solve(1,n);
            int q,xi;
            scanf("%d",&q);
            while(q--){
                scanf("%d",&xi);
                if(m.count(xi)) printf("%I64d
    ",m[xi]);
                else puts("0");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    JavaScript界面传值与前后台互调
    @requestBody注解的使用
    mybatis动态sql中foreach标签的使用
    mybatis动态SQL中的sql片段
    mybatis动态sql中where标签的使用
    mybatis动态sql中的trim标签的使用
    mybatis动态SQL中的set标签的使用
    SQL-join(inner join)、left join、right join、full join
    Oracle-distinct()用法、count(distinct( 字段A || 字段B))是什么意思?distinct多个字段
    Oracle-where exists()、not exists() 、in()、not in()用法以及效率差异
  • 原文地址:https://www.cnblogs.com/chanme/p/4008782.html
Copyright © 2011-2022 走看看