CTSC2013 没头脑和不高兴

没头脑和不高兴

对于一个随机的 \(n\) 元排列,指定一些位置将其排好序。 回答关于新序列逆序对的期望与方差的若干问题:

  1. 所排序的位置为所有编号为奇数的位置,求期望与方差。(40%)

  2. 所排序的位置进行 \(q\) 次区间修改,求每次修改后的期望。(50%)

  3. 两问全部回答正确可获得10%bonus

\(n,q≤10^5\)

题解

艾雨青《没头脑和不高兴》

brothers

期望 \(E(I_n)\)

把期望拆开计算:
\[ E(I_n)=\sum_{i=1}^{n-1}\sum_{j=i+1}^n P_{i,j} \]
其中 \(P_{i,j}\) 是位置 \((i,j)\) 是逆序对的概率,分情况讨论:

  1. \(i,j\) 均被选中排序,\(P_{i,j}=0\)

  2. \(i,j\) 均未被选中, \(P_{i,j}=\frac{1}{2}\)

  3. \(i\) 被选中,\(j\) 未被选中,\(P_{i,j}=?\)

  4. \(i\) 未被选中,\(j\) 被选中,\(P_{i,j}=?\)

考虑这样一个问题,在 \(n\) 个数中选择 \(m\) 个拿出来排好序,再在剩下的 \(n-m\) 个数中挑一个。那么这个数比之前的 \(m\) 个数中第 \(k\) 小的数还要小的概率有多大?

这样考虑这个问题,一开始就直接选出 \(m+1\) 个数排好序, 再在里面挑出未排序的那个数。所以答案是 \(\frac{k}{m+1}\)

所以上述情况3、4的贡献为:

  1. \(i\) 被选中,\(j\) 未被:\(P_{i,j}=\frac{V_i}{Total+1}\)

  2. \(i\) 未被选中,\(j\) 被选中,\(P_{i,j}=\frac{Total+1-V_j}{Total+1}\)

其中 \(Total\) 是总共被选中的位置个数,\(V_i\) 指的是被选中的位置 \(i\) 是所有被选中的位置中第几小的。

第一问中的 \(E(I_n)\)

  • \(n\) 为偶数时,设长度为 \(2n\)

    \[ E(I_{2n})=\sum_{i=1}^{2n-1}\sum_{j=i+1}^{2n}P_{i,j}\\ =\frac{1}{2}\binom{n}{2} +\left(\frac{1\times n}{n+1}+\frac{2\times (n-1)}{n+1}+\dots+\frac{n\times 1}{n+1}\right) +\left(\frac{1\times (n-1)}{n+1}+\frac{2\times (n-2)}{n+1}+\dots+\frac{(n-1\times 1}{n+1}\right)\\ \]

    第一项表示情况2,第二项表示情况3,第三项表示情况4。

    \[ E(I_{2n})=\frac{n(n-1)}{4} +\frac{\sum_{i=1}^ni(n+1-i)}{n+1}+\frac{\sum_{i=1}^{n-1}i(n-i)}{n+1}\\ =\frac{n(n-1)}{4} +\frac{1}{n+1}\left(\frac{n(n+1)^2}{2}-\frac{n(n+1)(2n+1)}{6}+\frac{(n-1)n^2}{2}-\frac{(n-1)n(2n-1)}{6}\right)\\ =\frac{7n^2-n}{12} \]

  • \(n\) 为奇数时,设长度为 \(2n+1\)

    \[ E(I_{2n+1})=\sum_{i=1}^{2n}\sum_{j=i+1}^{2n+1}P_{i,j}\\ =\frac{1}{2}\binom{n}{2} +\left(\frac{1\times n}{n+2}+\frac{2\times (n-1)}{n+2}+\dots+\frac{n\times 1}{n+2}\right) +\left(\frac{1\times n}{n+2}+\frac{2\times (n-1)}{n+2}+\dots+\frac{n\times 1}{n+2}\right) \]

    第一项表示情况2,第二项表示情况3,第三项表示情况4。
    \[ E(I_{2n+1})=\frac{n(n-1)}{4}+\frac{2}{n+2}\left(\frac{n(n+1)^2}{2}-\frac{n(n+1)(2n+1)}{6}\right)\\ =\frac{7n^2+n}{12} \]

第二问中的维护 \(E(I_n)\)

  • 第1、2种情况不用维护。

  • 第3种情况,\(P_{i,j}=\frac{V_i}{Total+1}\)

    换一种角度,对于固定的 \(j\) 考虑前面 \(i\) 的贡献。

    \(j\) 前面有 \(k\)\(i\),即 \(k\) 个选定的位置,那么对答案的贡献之和为

    \[ \frac{1}{Total+1}+\frac{2}{Total+1}+\dots+\frac{k}{Total+1}\\ =\frac{1}{Total+1}\times \frac{k(k+1)}{2} \]
    那么如何维护 \(\frac{k(k+1)}{2}\) 呢?注意到 \(\frac{k(k+1)}{2}=\binom{k}{2}+k\),所以我们可以把选定的位置视作1,未选定的位置视作0,转而统计子序列110的个数+子序列10的个数。

  • 第4种情况,\(P_{i,j}=\frac{Total+1-V_j}{Total+1}\)

    换一种角度,对于固定的 \(i\) 考虑后面 \(j\) 的贡献。

    \(i\) 后面有 \(k\)\(j\),即 \(k\) 个选定的位置,那么对答案的贡献之和为

    \[ \frac{1}{Total+1}+\frac{2}{Total+1}+\dots+\frac{k}{Total+1}\\ =\frac{1}{Total+1}\times \frac{k(k+1)}{2} \]

    于是我们可以转而统计子序列011的个数+子序列01的个数。

线段树维护区间各种子序列的个数0、1、01、10、110、011。

第一问中的 \(Var(I_n)\)

\(Var(I_n)=E(I_n^2)-E(I_n)^2\),只需求平方的期望。
\[ E(I_n^2)=\sum_{i_1=1}^{n-1}\sum_{j_1=i_1+1}^{n}\sum_{i_2=1}^{n-1}\sum_{j_2=i_2+1}^nP_{i_1,j_1}\times P_{i_2,j_2} \]
分情况讨论?\(i_1,j_1,i_2,j_2\) 可能有不同的奇偶性组合,不同的顺序,还可能重合到一起。少说也有三四十种情况吧。

大胆的猜想将加快你的解题速度!第一问中的期望是一个只跟 \(n\) 有关的多项式,那么方差是不是也会是呢?

\(n\) 的奇偶性相同时,我们假设方差是一个只与 \(\lfloor\frac{n}{2}\rfloor\) 有关并且次数不高的多项式,通过搜索程序我们可以得到小数据的答案。

拉格朗日插值法。系数的分子分母不会很大?暴力枚举系数!

  • \(n\) 为偶数时,设长度为 \(2n\)\(Var(I_{2n+1})=\frac{54n^3+13n^2+23n}{360}\)

  • \(n\) 为奇数时,设长度为 \(2n+1\)\(Var(I_{2n})=\frac{54n^3+55n^2-29n}{360}\)

拉格朗日插值找次数。暴力枚举分母的时候要保证乘起来是整数,这样能加速枚举。

代码

虽然题目要求输出分数,但是上述分析说明了我们的算法主要是在计数,即古典概型,不用写分数类。

时间复杂度 \(O(n\log n)\)

struct node {LL c0,c1,c01,c10,c011,c110;};
node operator+(CO node&a,CO node&b){
    node ans=(node){a.c0+b.c0,a.c1+b.c1};
    ans.c01=a.c01+a.c0*b.c1+b.c01;
    ans.c10=a.c10+a.c1*b.c0+b.c10;
    ans.c011=a.c011+a.c01*b.c1+a.c0*b.c1*(b.c1-1)/2+b.c011;
    ans.c110=a.c110+a.c1*(a.c1-1)/2*b.c0+a.c1*b.c10+b.c110;
    return ans;
}

CO int N=1e5+10;
node tree[4*N];
int tag[4*N];

#define lc (x<<1)
#define rc (x<<1|1)
void build(int x,int l,int r){
    tag[x]=-1;
    if(l==r){
        tree[x]=l&1?(node){0,1}:(node){1,0};
        return;
    }
    int mid=(l+r)>>1;
    build(lc,l,mid),build(rc,mid+1,r);
    tree[x]=tree[lc]+tree[rc];
}
void push_down(int x,int l,int r){
    if(tag[x]==-1) return;
    int mid=(l+r)>>1;
    if(tag[x]==0){
        tree[lc]=(node){mid-l+1,0},tag[lc]=0;
        tree[rc]=(node){r-mid,0},tag[rc]=0;
    }
    else{
        tree[lc]=(node){0,mid-l+1},tag[lc]=1;
        tree[rc]=(node){0,r-mid},tag[rc]=1;
    }
    tag[x]=-1;
}
void change(int x,int l,int r,int ql,int qr,int v){
    if(ql<=l and r<=qr){
        tree[x]=v==0?(node){r-l+1,0}:(node){0,r-l+1},tag[x]=v;
        return;
    }
    push_down(x,l,r);
    int mid=(l+r)>>1;
    if(ql<=mid) change(lc,l,mid,ql,qr,v);
    if(qr>mid) change(rc,mid+1,r,ql,qr,v);
    tree[x]=tree[lc]+tree[rc];
}

int main(){
    int n=read<int>();
    LL x=n/2;
    if(n&1){
        LL a=7*x*x+x,b=12,g=gcd(a,b);
        printf("%lld/%lld\n",a/g,b/g);
        a=54*x*x*x+55*x*x-29*x,b=360,g=gcd(a,b);
        printf("%lld/%lld\n",a/g,b/g);
    }
    else{
        LL a=7*x*x-x,b=12,g=gcd(a,b);
        printf("%lld/%lld\n",a/g,b/g);
        a=54*x*x*x+13*x*x+23*x,b=360,g=gcd(a,b);
        printf("%lld/%lld\n",a/g,b/g);
    }
    build(1,1,n);
    for(int m=read<int>();m--;){
        int l=read<int>(),r=read<int>(),v=read<int>();
        change(1,1,n,l,r,v);
        CO node&t=tree[1];
        LL a1=t.c0*(t.c0-1),b1=4;
        LL a2=t.c01+t.c10+t.c011+t.c110,b2=t.c1+1;
        LL a=a1*b2+a2*b1,b=b1*b2,g=gcd(a,b);
        printf("%lld/%lld\n",a/g,b/g);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12109591.html