• newker训练营4


    T1:

    长度为n数组循环k次,求1<=l<=r<=n*k, l~r中不同权值个数的总和。

    总长(i+1)*i/2,减去相同数:考虑相同数造成贡献,发现是减去上一个相同权值出现的位置下标。继承之前减去的。

    算出长度<n的,>=n恒为cnt.

    乘上系数:整个序列出现次数。

    注意:n<i<n*2时,只计算跨区间的,还要减去不跨区间的。避免重复也要减去len>=n的。

    #include<bits/stdc++.h>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define LL long long
    #define pf(a) printf("%lld ",a)
    #define phn puts("")
    using namespace std;
    #define int LL
    int read();
    #define N 200010
    const int mod=1e9+7,inv2=500000004;
    LL n,K;
    int a[N],las[N],head[N],f[N];
    map<int,int>mp;int cnt;
    LL qpow(int x,int k){int s=1;x%=mod;for(;k;k>>=1,x=x*x%mod)if(k&1)s=s*x%mod;return s;}
    signed main(){
    //  freopen("a.in","r",stdin);
        n=read();K=read();
        F(i,1,n){
            a[i]=read();
            if(!mp[a[i]])mp[a[i]]=++cnt;
            a[i]=mp[a[i]];
            las[i]=head[a[i]];head[a[i]]=i;
        }
        F(i,n+1,n+n){a[i]=a[i-n];las[i]=head[a[i]];head[a[i]]=i;}
        LL ans=0,w=0,sum=0;/** ans=(ans%mod+mod)%mod;*/
        for(LL i=1;i<=n;++i){
            sum+=las[i];
            w=((i+1)*i/2-sum)%mod;
            if(i==n){w-=cnt;}
            f[i]=w;
            ans=(ans+f[i]*K)%mod;
        }
        sum%=mod;
        for(LL i=n+1;i<n+n;++i){
            sum+=las[i];
            w=((i+1)*i/2-sum-(i-n+1)*cnt-f[i-n])%mod;
            ans=(ans+w*(K-1))%mod;
        //  pf(sum);pf(w*(K-1));phn;
        }
        LL x=(n*K-n+1)%mod;
        w=(x+1)*x/2%mod;
        ans=((ans+w*cnt)%mod+mod)%mod;
        printf("%lld
    ",ans);
    }
    int read(){
        int s=0,f=0;char ch=getchar();
        while(!isdigit(ch))f=ch=='-',ch=getchar();
        while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
        return f?-s:s;
    }
    /*
    g++ 1.cpp
    ./a.out
    3 2
    1 2 2
    */
    View Code

    T2:

    树上差分、前缀和、dfs序的应用。

    只询问p,q路径,可以n^2.没必要树形DP。

    直接n^2枚举点对O(1)算距离即可。

    考虑枚举点对i,j,O(1)统计。

    求出以i为lca的路径数和经过i且不以i为lca的路径数。

    u=lca(i,j)。

    w=u子树和,减去i~j链上,加上u子树外,减去经过u且不以u为lca条数。

    先往简单想。别过于套路,一看路径长直接树DP。

    好题。

    B@哥 真巨。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    inline void read(int &x)
    {
        x=0;char c=getchar();
        while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48,c=getchar();
    }
    typedef long long ll;
    const int maxn=3005;
    int n,p,q,tot,dex,fr[maxn],first[maxn],dep[maxn],f[maxn];
    ll ans,res,dp[maxn],dis[maxn],g[maxn],h[maxn];
    struct Road{
        int u,t,nxt;
    }eage[maxn<<1];
    void add(int x,int y) {eage[++tot]=(Road){x,y,first[x]};first[x]=tot;}
    struct ST_Table{
        int p,f[maxn<<1][22],len[maxn<<1],bin[22];
        void init()
        {
            p=log(dex)/log(2)+1;
            for(int i=bin[0]=1;i<=p;++i) bin[i]=bin[i-1]<<1;
            for(int i=1;i<=dex;++i) len[i]=log(i)/log(2);
            for(int j=1;j<=p;++j)
                for(int i=1;i+bin[j]-1<=dex;++i)
                {
                    if(dep[f[i][j-1]]<dep[f[i+bin[j-1]][j-1]]) f[i][j]=f[i][j-1];
                    else f[i][j]=f[i+bin[j-1]][j-1];
                }
        }
        int LCA(int x,int y)
        {
            if(fr[x]>fr[y]) swap(x,y);
            int l=len[fr[y]-fr[x]+1];
            if(dep[f[fr[x]][l]]<dep[f[fr[y]-bin[l]+1][l]]) return f[fr[x]][l];
            else return f[fr[y]-bin[l]+1][l];
        }
    }ST;
    ll Get_dep(int x,int y) {return dep[x]+dep[y]-2*dep[ST.LCA(x,y)];}
    void frdfs(int x,int fa)
    {
        ST.f[fr[x]=++dex][0]=x;dep[x]=dep[fa]+1;f[x]=fa;
        for(int i=first[x];i;i=eage[i].nxt)
            if(eage[i].t!=fa)
            {
                frdfs(eage[i].t,x);
                ST.f[++dex][0]=x;
            }
    }
    void redfs(int x,int fa)
    {
        for(int i=first[x];i;i=eage[i].nxt)
            if(eage[i].t!=fa)
            {
                redfs(eage[i].t,x);
                dp[x]+=dp[eage[i].t];
            }
    }
    void lsdfs(int x,int fa)
    {
        h[x]=h[fa]+g[x];
        for(int i=first[x];i;i=eage[i].nxt)
            if(eage[i].t!=fa)
            {
                lsdfs(eage[i].t,x);
                g[x]+=g[eage[i].t];
            }
    }
    int main()
    {
        read(n);read(p);read(q);
        for(int i=1,x,y;i<=n-1;++i)
        {
            read(x);read(y);
            add(x,y);add(y,x);
        }
        frdfs(1,0);
        ST.init();
        for(int i=1;i<=n;++i)
            for(int j=1,lca;j<=n;++j)
                if(Get_dep(i,j)==p)
                {
                    lca=ST.LCA(i,j);++g[lca];
                    ++dp[i];++dp[j];--dp[lca];--dp[lca];
                }
        redfs(1,0);lsdfs(1,0);
        dp[0]=dp[1];g[0]=g[1];
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                if(Get_dep(i,j)==q)
                {
                    int lca=ST.LCA(i,j);
                    ans+=g[lca]-(h[i]+h[j]-h[lca]-h[f[lca]]);
                    ans+=g[1]-g[lca]-dp[lca];
                    /** 经过该点且不以该点为lca的边数。*/
                }
        printf("%lld
    ",ans);
        return 0;
    }
    lnc代码

    我的n^2递推,利用dfs序预处理lca.

    下面是 B&哥 思路:g[i][j],表示以dfs序上ij位置两点为端点路径数。

    用来计算u子树外的部分:由于dfs序是连续段,则i,j均不在u子树dfs序范围内即可。

    g数组的处理有个细节调了半天,注释上了。

    #include<bits/stdc++.h>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define LL long long
    #define pf(a) printf("%d ",a)
    #define PF(a) printf("%lld ",a)
    #define phn puts("")
    using namespace std;
    int read();
    #define N 3005
    int n,p,q;
    int to[N<<1],fir[N<<1],head[N],cnt;
    void add(int x,int y){to[++cnt]=y;fir[cnt]=head[x];head[x]=cnt;}
    int fa[N],dep[N],L[N],dfn[N],R[N],tot;
    void dfs(int x,int Fa){
        dep[x]=dep[Fa]+1;fa[x]=Fa;L[x]=++tot;dfn[tot]=x;
        for(int i=head[x],v;i;i=fir[i])if(!dep[v=to[i]]){
            dfs(v,x);
        }
        R[x]=tot;
    }
    int lca[N][N];
    LL w[N],g[N][N],sub[N],up[N],ans;
    void push(int x){
        sub[x]=w[x];up[x]=up[fa[x]]+w[x];
        for(int i=head[x],v;i;i=fir[i])if((v=to[i])^fa[x]){
            push(v);sub[x]+=sub[v];
        }
    }
    /*g++ 2.cpp
    ./a.out
    */
    void cal(int x,int y){
        int u=lca[x][y];
        ans+=sub[u];
        ans-=up[x]+up[y]-up[u]-up[fa[u]];
        int l=L[u],r=R[u];
        ans+=g[l-1][l-1];
        ans+=g[l-1][n]-g[l-1][r];
        ans+=g[n][l-1]-g[r][l-1];
        ans+=g[n][n]-g[n][r]-g[r][n]+g[r][r];
    //    if(x==3&&y==5){PF(ans);}
    }
    int main(){
       freopen("b.in","r",stdin);
    //    freopen("2.in","r",stdin);//freopen("2.out","w",stdout);
        n=read();p=read();q=read();
        for(int i=1,u,v;i<n;++i){
            u=read();v=read();add(u,v);add(v,u);
        } 
        dfs(1,0);
        F(i,1,n){
            lca[i][i]=i;
            F(j,L[i]+1,R[i])lca[i][dfn[j]]=lca[dfn[j]][i]=i;
            for(int j=L[i]+1;j<=R[i];j=R[dfn[j]]+1){
                for(int k=j;k<=R[dfn[j]];++k){
                    for(int h=R[dfn[j]]+1;h<=R[i];++h){
                        lca[dfn[k]][dfn[h]]=lca[dfn[h]][dfn[k]]=i;
                    }
                }
            }
        }
        F(i,1,n){
            F(j,1,n){
                if(dep[i]+dep[j]-dep[lca[i][j]]*2==q){
                    ++w[lca[i][j]];++g[L[i]][L[j]];
                    /** 注意:这里是g[L[i]],加到dfs序对应位置。*/
                }
            }
        }
        F(i,1,n){
            F(j,1,n){
                g[i][j]=g[i][j-1]+g[i-1][j]+g[i][j]-g[i-1][j-1];
            }
        }
     //   F(i,1,n)pf(dfn[i]);phn;phn;
      //  F(i,1,n){F(j,1,n)PF(g[i][j]);phn;}phn;
        push(1);
        F(i,1,n){
            F(j,1,n){
                if(dep[i]+dep[j]-dep[lca[i][j]]*2==p){
                    cal(i,j);
      //              pf(i);pf(j);pf(ans);phn;
                }
            }
        }
        printf("%lld
    ",ans);
    }
    int read(){
        int s=0,f=0;char ch=getchar();
        while(!isdigit(ch))f=ch=='-',ch=getchar();
        while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
        return f?-s:s;
    }
    /*
    g++ d2.cpp
    ./a.out
    g++ 2.cpp
    ./a.out
    g++ bsgs.cpp
    ./a.out
    10 2 3 
    2 1 
    3 1 
    4 1 
    5 3 
    6 3 
    7 6 
    8 6 
    9 6 
    10 7
    g++ 2.cpp
    ./a.out
    8 2 2
    1 2
    1 3
    2 4
    2 5
    4 6
    4 7
    5 8
    g++ 2.cpp
    ./a.out
    5 2 1
    1 2
    2 3
    3 4
    2 5
    g++ 2.cpp
    ./a.out
    4 1 1
    1 2
    2 3
    3 4
    */
    View Code

     T3:

    DP:f[j][k]表示最大值为j,权值k次方的和。
    考虑在已经扫过的一段序列后面增加一个的贡献:
    w^k->(w+1)^k
    =sigma:w^h*C(k,h).
    则对于每个k次方可以求和,共同计算。

    纯DP N^2.线段树优化,类似队长快跑。

    #include<bits/stdc++.h>
    #define F(i,a,b) for(int i=a;i<=b;++i)
    #define LL long long
    #define pf(a) printf("%d ",a)
    #define PF(a) printf("%lld ",a)
    #define phn puts("")
    using namespace std;
    #define int LL 
    int read();
    #define N 100010
    #define int LL 
    const int mod=1e9+7;
    int n,m,a[N],f[N][22],sum[22],plu[22],C[22][22];
    int MO(int x){return x<mod?x:x-=mod;}
    /**
    DP:f[j][k]表示最大值为j,权值k次方的和。
    考虑在已经扫过的一段序列后面增加一个的贡献:
    w^k->(w+1)^k
    =sigma:w^h*C(k,h).
    则对于每个k次方可以求和,共同计算。
    */
    struct SEG{
        struct nodi{
            int l,r,g,w[22];
        }s[N<<2];
        #define sx s[x]
        #define lc s[x<<1]
        #define rc s[x<<1|1]
        #define MIT int z=sx.l+sx.r>>1
        void biu(int x,int l,int r){
            sx.l=l;sx.r=r;sx.g=1;
            if(l==r)return ;MIT;
            biu(x<<1,l,z);biu(x<<1|1,z+1,r);
        }
        void down(int x){
            if(sx.g>1){
                F(i,0,20){lc.w[i]=lc.w[i]*sx.g%mod;rc.w[i]=rc.w[i]*sx.g%mod;}
                lc.g=lc.g*sx.g%mod;rc.g=rc.g*sx.g%mod;sx.g=1;
            }
        }
        void up(int x){
            F(i,0,20)sx.w[i]=MO(lc.w[i]+rc.w[i]);
        }
        void mpl(int x,int l,int r){
            if(l<=sx.l&&sx.r<=r){
                F(i,0,20)sx.w[i]=sx.w[i]*2%mod;
                sx.g=sx.g*2%mod;
                return ;
            }MIT;down(x);
            if(l<=z)mpl(x<<1,l,r);if(r>z)mpl(x<<1|1,l,r);up(x);
        }
        void ask(int x,int l,int r){
            if(l<=sx.l&&sx.r<=r){
                F(i,0,20)sum[i]=MO(sum[i]+sx.w[i]);
                return ;
            }MIT;down(x);
            if(l<=z)ask(x<<1,l,r);if(r>z)ask(x<<1|1,l,r);
        }
        void add(int x,int p){
            if(sx.l==sx.r){
                F(i,0,20)sx.w[i]=MO(sx.w[i]+plu[i]);
                return ;
            }MIT;down(x);
            add((p<=z?(x<<1):(x<<1|1)),p);up(x);
        }
    }sg;
    signed main(){
    //    freopen("c.in","r",stdin);
        /** 区间乘2,单点加,区间求和。*/
        n=read();m=read();
        F(i,1,n)a[i]=read();
        C[0][0]=1;
        F(i,1,20){
            C[i][0]=1;F(j,1,i)C[i][j]=MO(C[i-1][j-1]+C[i-1][j]);
        }
        sg.biu(1,1,n);
        F(i,1,n){
            F(k,0,m)plu[k]=1;
    //        F(j,a[i]+1,n)F(k,0,m)f[j][k]=MO(f[j][k]<<1);
            sg.mpl(1,a[i]+1,n);
    //        F(j,1,a[i]-1)F(k,0,m)w[k]+=f[j][k];
            sg.ask(1,1,a[i]-1);
            F(k,0,m){
                F(h,0,k){
                    plu[k]=(plu[k]+sum[h]*C[k][h])%mod;
                }
            }
            sg.add(1,a[i]);
            F(k,0,m)sum[k]=plu[k]=0;
        }
        LL ans=(sg.s[1].w[m]%mod+mod)%mod;
        printf("%lld
    ",ans);
    }
    int read(){
        int s=0,f=0;char ch=getchar();
        while(!isdigit(ch))f=ch=='-',ch=getchar();
        while(isdigit(ch))s=s*10+(ch^48),ch=getchar();
        return f?-s:s;
    }
    /*
    g++ 3.cpp
    ./a.out
    3 2
    1 3 2
    */
    View Code
  • 相关阅读:
    初探 Redis 客户端 Lettuce:真香!
    vscode 代码中查找并替换为换行符
    Jenkins Kubernetes插件添加 云
    Jenkins kubernetes插件的原理
    jenkins pipeline实现自动构建并部署至k8s
    python3 requests中的 stream参数
    rsync 开启用户密码认证
    rancher1版本 基本使用
    nginx http跳https
    sed合并多条指令修改文本
  • 原文地址:https://www.cnblogs.com/seamtn/p/11803304.html
Copyright © 2020-2023  润新知