zoukankan      html  css  js  c++  java
  • [CodeCraft-20 (Div. 2)][Codeforces 1316F. Battalion Strength]

    题目链接:1316F - Battalion Strength

    题目大意:对于一个序列(left {  a_n ight }),定义其权值为,将其排序后,(sum_{i=1}^{n-1}a_icdot a_{i+1})的值。现在给出一个数组,要求每次修改其中一个位置的值,并求出修改后随机选取一个子序列的权值的期望

    题解:先考虑对于一个有序数组(left {  a_n ight })对应的答案是多少

       对于任一一对满足(1le i < j le n)的((i,j)),能够让(a_i)与(a_j)相邻的子序列个数为(2^{n-(j-i+1)}),因此我们可以得出最开始的式子

    $$ans=frac{sum_{i=1}^nsum_{j=i+1}^n a_icdot a_j cdot 2^{n-j+i-1}}{2^n}$$

       把分母消掉后得出

    $$ans=sum_{i=1}^nsum_{j=i+1}^n a_icdot a_j cdot 2^{i-j-1}$$

       因此如果没有修改操作,我们就可以直接把原数组进行排序后,用分治的思想(线段树)求出答案

       对于有修改的情况,我们可以把修改的值加进来一起排序,这样就可以通过用线段树维护目前有哪些数存在来得出答案。对于每个结点,我们维护对应区间内有值的位置个数(c),对应的答案(ans),这个区间在左边或右边时需要乘上的系数(sl,sr)

       而对于这个系数,我们可以通过回顾之前的那个式子发现,每对((i,j))的贡献是(2^{i-j-1})。这时如果直接分别维护(a_icdot 2^i)和(a_icdot 2^{-i})的值,在合并时会出现不小的麻烦。因为假设左区间有(n_l)个位置有值 ,其第(i)个元素(l_i)与右区间的第(j)个元素(r_j)合并时。我们会发现在新区间中,(r_j)不再是区间的第(j)个元素了,而是第(n_l+j)个。但是我们又可以发现,在新的区间里,他们的贡献变成了(2^{i-(n_l+j)+1}=2^{i-n_l-j-1}=2^{-(n_l-i+1)}cdot 2^{-j})。这样的话我们对于一个区间内的数,只需令(sl=sum_{i=1}^{c}b_icdot 2^{-(c-i+1)},sr=sum_{i=1}^{c}b_icdot 2^{-i})即可,其中(b_i)为区间内第(i)个非空位置对应的值

       这样我们就可以排序后,先把每个(left {  a_n ight })对应的位置设为有值的状态,之后每次询问只需把对应修改的位置置零,新值对应的位置设为有值即可,注意修改后由于(a_i)的值发生了改变,其对应的位置也要进行变化

    #include<bits/stdc++.h>
    using namespace std;
    #define N 600001
    #define MOD 1000000007
    int n,m,p[N],q[N],I[N],v;
    struct pi
    {
        int v,id;
        void read(int i){scanf("%d",&v),id=i;}
        bool operator <(const pi &t)const{return v<t.v;}
    }a[N];
    struct rua
    {
        int c,ans,sl,sr;
    }t[N<<2];
    void change(int x,int i,int l,int r,int o)
    {
        if(l==r)
          {
          t[i].c=o;
          t[i].ans=t[i].sl=t[i].sr=0;
          if(o)t[i].sl=t[i].sr=1ll*I[1]*a[x].v%MOD;
          return;
          }
        int mid=l+r>>1,ls=i*2,rs=ls+1;
        if(x<=mid)change(x,ls,l,mid,o);
        else change(x,rs,mid+1,r,o);
        t[i].c=t[ls].c+t[rs].c;
        t[i].sl=(1ll*t[ls].sl*I[t[rs].c]+t[rs].sl)%MOD;
        t[i].sr=(1ll*t[rs].sr*I[t[ls].c]+t[ls].sr)%MOD;
        t[i].ans=(t[ls].ans+t[rs].ans+1ll*t[ls].sl*t[rs].sr)%MOD;
    }
    int main()
    {
        I[0]=1,I[1]=(MOD+1)/2;
        for(int i=2;i<N;i++)
          I[i]=1ll*I[1]*I[i-1]%MOD;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
          a[i].read(i),p[i]=i;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
          {
          scanf("%d",&q[i]);
          a[n+i].read(n+i);
          p[n+i]=n+i;
          }
        sort(a+1,a+n+m+1);
        for(int i=1;i<=n+m;i++)
          p[a[i].id]=i;
        for(int i=1;i<=n;i++)
          change(p[i],1,1,n+m,1);
        printf("%d
    ",t[1].ans);
        for(int i=1;i<=m;i++)
          {
          change(p[q[i]],1,1,n+m,0);
          change(p[n+i],1,1,n+m,1),p[q[i]]=p[n+i];
          printf("%d
    ",t[1].ans);
          }
    }
    View Code
  • 相关阅读:
    webapp开发绝对定位引发的问题
    git下配置github sshkey
    html5 filereader读取流注意事项
    神奇的负Margin
    泪奔的ie
    第二次作业-实践一 网络攻防环境的搭建
    20199115 2019-2020-2 《网络攻防实践》第一周作业
    《网络攻防实践》寒假作业
    C++中cin、cin.get()、cin.getline()、getline()、gets()等函数的用法
    getline()函数
  • 原文地址:https://www.cnblogs.com/DeaphetS/p/12421245.html
Copyright © 2011-2022 走看看