zoukankan      html  css  js  c++  java
  • 2020牛客国庆集训派对day1 B

    Description

    给定一个序列,求其所有子区间的 maxgcd 的乘积的和。

    Solution

    考虑枚举右端点,将右端点不断向右移动,同时维护 f[i] 表示 max(a[i],a[i+1],...,a[r]),维护 g[i] 表示 gcd(a[i],a[i+1],...,a[r]),维护 nxt[i] 表示最大的满足 g[nxt[i]]!=g[i] 的位置

    (注意 g[i] 并不需要实时维护,只要保证会用到的点是正确的就可以了)

    f[i] 用线段树和单调栈维护(需要支持区间修改和区间求和),g[i] 暴力维护即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    const int N = 1000005;
    const int mod = 1e+9+7;
    
    int a[N],f[N],g[N],nxt[N],n,val[N],sta[N],tag[N];
    
    void maintain(int p)
    {
        tag[p]%=mod;
        val[p]%=mod;
    }
    
    void pushup(int p)
    {
        val[p]=(val[p*2]+val[p*2+1])%mod;
    }
    
    void pushdown(int p,int l,int r)
    {
        if(tag[p])
        {
            tag[p*2]+=tag[p];
            tag[p*2+1]+=tag[p];
            val[p*2]+=tag[p]*((l+r)/2-l+1);
            val[p*2+1]+=tag[p]*(r-(l+r)/2);
            maintain(p*2);
            maintain(p*2+1);
            tag[p]=0;
        }
    }
    
    void modify(int p,int l,int r,int ql,int qr,int v)
    {
        if(l>qr || r<ql) return;
        if(l>=ql && r<=qr)
        {
            tag[p]+=v;
            val[p]+=v*(r-l+1);
            maintain(p);
        }
        else
        {
            pushdown(p,l,r);
            modify(p*2,l,(l+r)/2,ql,qr,v);
            modify(p*2+1,(l+r)/2+1,r,ql,qr,v);
            pushup(p);
        }
    }
    
    int query(int p,int l,int r,int ql,int qr)
    {
        if(l>qr || r<ql) return 0;
        if(l>=ql && r<=qr) 
        {
            return val[p];
        }
        else
        {
            pushdown(p,l,r);
            return (query(p*2,l,(l+r)/2,ql,qr)+query(p*2+1,(l+r)/2+1,r,ql,qr))%mod;
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=n;i++) nxt[i]=i-1, g[i]=a[i];
        int top=0,ans=0;
        for(int i=1;i<=n;i++)
        {
            while(top && a[sta[top]]<a[i])
            {
                modify(1,1,n,sta[top-1]+1,sta[top],-a[sta[top]]);
                --top;
            }
            modify(1,1,n,sta[top]+1,i,a[i]);
            sta[++top]=i;
            int pos=i;
            while(pos>0)
            {
                g[pos]=__gcd(g[pos],a[i]);
                while(__gcd(g[nxt[pos]],a[i])==__gcd(g[pos],a[i]) && nxt[pos]) 
                {
                    nxt[pos]=nxt[nxt[pos]];
                }
                ans+=query(1,1,n,nxt[pos]+1,pos)*g[pos]%mod;
                ans%=mod;
                pos=nxt[pos];
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    
  • 相关阅读:
    耶鲁大学——斯金纳理论基础
    耶鲁大学——弗洛伊德(基础)
    for input 'WID' 报错
    选中当前行wid
    微信支付
    vue.js列表渲染项目实例
    批量删除
    DIV 局部刷新
    DIV块刷新
    CMD DOS命令
  • 原文地址:https://www.cnblogs.com/mollnn/p/13786451.html
Copyright © 2011-2022 走看看