zoukankan      html  css  js  c++  java
  • dtoi4702 Gcd

    题意:

         有一个长度为n的互不相同的序列,求对于任意i,j,1<=i<=j<=n,求g(i,j)。

         g(i,j)的定义是将i~j的元素都删除之后剩余的数字两两之间gcd的最大值。

    题解:

         首先枚举gcd,考虑什么时候会作为答案。

         找到它的倍数所在的位置,假设从小到大所在的位置为a[0],a[1]...a[k],那么只需要有a[0],a[1]存在或者a[k-1],a[k]存在或者a[0],a[k]存在,然后其它区间乱删都没有关系。

         那么现在的问题就在于“区间乱删”时,会有好多之前已经计算过的答案被算了多次,显然是不行的。

         仔细思考我们要解决什么问题,现在我们需要做的事情就是给定一个区间l,r求l,r中剩余的子区间还有多少个。

         那我们先对于每一个位置i,记t[i]表示[i,i],[i,i+1]...[i,t[i]]这些区间已经被算过了。不难发现t[i]是单调的,因为如果大区间算过了,小区间一定也被算过了。

         那么l,r中剩余的子区间还有多少个要如何计算呢,其实答案就是[l,r]中,对于所有满足(t[i]<=r)的i,r-t[i]的总和。由于t[i]是单调的,所以在线段树上二分一下再求个和就行了。

         接下来我们把[l,r]中所有t[i]<=r的设置为t[i]=r,这依然可以线段树解决。于是就做完了这道题。

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int INF=1e9;
    int T,n,a[200002],min1[200002],min2[200002],max1[200002],max2[200002];
    typedef struct{
        int Min,f;
        long long sum;
    }P;
    P p[800002];
    long long ans;
    void build(int root,int begin,int end){
        if (begin==end)
        {
            p[root].Min=p[root].sum=begin-1;
            p[root].f=0;return;
        }
        int mid=(begin+end)/2;
        build(root*2,begin,mid);build(root*2+1,mid+1,end);
        p[root].Min=min(p[root*2].Min,p[root*2+1].Min);
        p[root].sum=p[root*2].sum+p[root*2+1].sum;
        p[root].f=0;
    }
    void pushdown(int root,int begin,int mid,int end){
        if (p[root].f)
        {
            p[root*2].Min=p[root].f;p[root*2+1].Min=p[root].f;
            p[root*2].sum=(long long)p[root].f*(mid-begin+1);p[root*2+1].sum=(long long)p[root].f*(end-mid);
            p[root*2].f=p[root].f;p[root*2+1].f=p[root].f;
            p[root].f=0;
        }
    }
    void gengxin(int root,int begin,int end,int begin2,int end2,int wz){
        if (begin>end2 || end<begin2)return;
        if (begin>=begin2 && end<=end2)
        {
            p[root].Min=p[root].f=wz;
            p[root].sum=(long long)wz*(end-begin+1);
            return;
        }
        int mid=(begin+end)/2;pushdown(root,begin,mid,end);
        gengxin(root*2,begin,mid,begin2,end2,wz);gengxin(root*2+1,mid+1,end,begin2,end2,wz);
        p[root].Min=min(p[root*2].Min,p[root*2+1].Min);
        p[root].sum=p[root*2].sum+p[root*2+1].sum;
    }
    int cx(int root,int begin,int end,int z){
        if (begin==end)return begin;
        int mid=(begin+end)/2;pushdown(root,begin,mid,end);
        if (p[root*2+1].Min<=z)return cx(root*2+1,mid+1,end,z);
        else return cx(root*2,begin,mid,z);
    }
    int chaxun(int root,int begin,int end,int begin2,int end2){
        if (begin>end2 || end<begin2)return begin2-1;
        if (begin>=begin2 && end<=end2)
        {
            if (p[root].Min<=end2)return cx(root,begin,end,end2);
            return begin2-1;
        }
        int mid=(begin+end)/2;pushdown(root,begin,mid,end);
        int t1=chaxun(root*2+1,mid+1,end,begin2,end2);
        if (t1>=begin2)return t1;
        else return chaxun(root*2,begin,mid,begin2,end2);
    }
    long long cxsum(int root,int begin,int end,int begin2,int end2){
        if (begin>end2 || end<begin2 || begin2>end2)return 0;
        if (begin>=begin2 && end<=end2)return p[root].sum;
        int mid=(begin+end)/2;pushdown(root,begin,mid,end);
        return cxsum(root*2,begin,mid,begin2,end2)+cxsum(root*2+1,mid+1,end,begin2,end2); 
    }
    long long js(int x,int y){
        if (x<0 || x>n || y<0 || y>n || x==y)return 0;
        long long ans=0;
        if (x>1)
        {
            int ef=chaxun(1,1,n,1,x-1);
            ans+=((long long)(x-1)*ef-cxsum(1,1,n,1,ef));
            gengxin(1,1,n,1,ef,x-1);
        }
        if (x+1<=y-1)
        {
            int ef=chaxun(1,1,n,x+1,y-1);
            ans+=((long long)(y-1)*(ef-x)-cxsum(1,1,n,x+1,ef));
            gengxin(1,1,n,x+1,ef,y-1);
        }
        if (y<n)
        {
            int ef=chaxun(1,1,n,y+1,n);
            ans+=((long long)n*(ef-y)-cxsum(1,1,n,y+1,ef));
            gengxin(1,1,n,y+1,ef,n);
        }
        
        return ans;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);int Max=0;ans=0;
            for (int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                Max=max(Max,a[i]);
            }
            for (int i=1;i<=Max;i++)
            {
                min1[i]=min2[i]=INF;
                max1[i]=max2[i]=-INF;
            }
            for (int i=1;i<=n;i++)
            {
                if (min1[a[i]]==INF)min1[a[i]]=i;
                else if (min2[a[i]]==INF)min2[a[i]]=i;
            }
            for (int i=n;i>=1;i--)
            {
                if (max1[a[i]]==-INF)max1[a[i]]=i;
                else if (max2[a[i]]==-INF)max2[a[i]]=i;
            }
            build(1,1,n);
            for (int i=Max;i>=1;i--)
            {
                int mi1=INF,mi2=INF,mx1=-INF,mx2=-INF;
                for (int j=i;j<=Max;j+=i)
                {
                    if (min1[j]<mi1)
                    {
                        mi2=mi1;mi1=min1[j];
                    }
                    else mi2=min(mi2,min1[j]);
                    if (min2[j]<mi1)
                    {
                        mi2=mi1;mi1=min2[j];
                    }
                    else mi2=min(mi2,min2[j]);
                    if (max1[j]>mx1)
                    {
                        mx2=mx1;mx1=max1[j];
                    }
                    else mx2=max(mx2,max1[j]);
                    if (max2[j]>mx1)
                    {
                        mx2=mx1;mx1=max2[j];
                    }
                    else mx2=max(mx2,max2[j]);
                }
                ans+=i*(js(mx2,mx1)+js(mi1,mx1)+js(mi1,mi2));
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    June. 26th 2018, Week 26th. Tuesday
    June. 25th 2018, Week 26th. Monday
    June. 24th 2018, Week 26th. Sunday
    June. 23rd 2018, Week 25th. Saturday
    June. 22 2018, Week 25th. Friday
    June. 21 2018, Week 25th. Thursday
    June. 20 2018, Week 25th. Wednesday
    【2018.10.11 C与C++基础】C Preprocessor的功能及缺陷(草稿)
    June.19 2018, Week 25th Tuesday
    June 18. 2018, Week 25th. Monday
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12257659.html
Copyright © 2011-2022 走看看