zoukankan      html  css  js  c++  java
  • [JZOJ6340] 【NOIP2019模拟2019.9.4】B

    题目

    题目大意

    给你个非负整数数列(a),每次等概率选择大于零的(a_i),使其减(1)
    (a_1)被减到(0)的时候期望经过多少次操作。


    思考历程

    对于这题的暴力做法,显然可以状态压缩吧……
    然后我突然意识到,实际上我们将题目转化成以下模型:
    (n)种颜色,第(i)种颜色的小球有(a_i)个。那么题目就变成了一个有重复元素的排列问题。
    先将(2)(n)排列求出来,然后考虑将(1)随机插入。
    枚举最后一个(1)出现的位置,然后在前面用组合数计算插入的方案数。
    这个做法打出来之后一直没有调出来,也不知道是我数学功底不好还是这个方法本来就是错的……
    当然,即便是对的,也不会是满分做法。


    正解

    根据期望的线性性,题目可以转化为:对于每个(i>1)(a_1)减到(0)的时候(a_i)期望取了多少个。然后将每个(i)的这东西加起来,再加上(a_1),就是答案。
    于是我们就只需要考虑这个问题。
    接着就是最骚的操作:我们只考虑(a_1)(a_i),其它被减掉对它们没有影响。它们有相等的概率被减(1),这个概率可以看做是(frac{1}{2})。于是相当于题目中(n=2)的情况。
    现在考虑一个平面,一开始的坐标为((a_1,a_i)),每次随机地向下面或者左边走一格。
    如果到达边界((0,y)),则会有(a_i-y)的贡献;如果到达边界((x,0)),则会有(a_i)的贡献。
    对于边界((0,y)),设向下走了(j)步,则概率为(frac{C_{a_1+j-1}^{j}}{2^{a_1+j}})
    对于边界((x,0)),既然它们的贡献都一样,不妨将上面的和用(1)减掉,就是它的概率。
    接着就可以列出一个式子……
    列出之后容易发现,((a_1,a_i+1))的答案可以(O(1))地从((a_i,a_i))转移过来。


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cassert>
    #define N 500010
    #define A 500010
    #define mo 323232323
    inline int input(){
    	char ch=getchar();
    	while (ch<'0' || '9'<ch)
    		ch=getchar();
    	int x=0;
    	do{
    		x=x*10+ch-'0';
    		ch=getchar();
    	}
    	while ('0'<=ch && ch<='9');
    	return x;
    }
    int n,a[N];
    int fac[N+A],invf[N+A],inv2[N+A];
    int ans1[A*3],ans2[A*3],ans[A*3];
    inline int inv(int x){
    	int res=1;
    	for (int y=mo-2;y;y>>=1,x=(long long)x*x%mo)
    		if (y&1)
    			res=(long long)res*x%mo;
    	return res;
    }
    inline int C(int m,int n){return (long long)fac[m]*invf[n]%mo*invf[m-n]%mo;}
    int main(){
    	freopen("b.in","r",stdin);
    	freopen("b.out","w",stdout);
    	n=input();
    	for (int i=1;i<=n;++i)
    		a[i]=input();
    	fac[0]=1,inv2[0]=1;
    	for (int i=1;i<=A*2;++i){
    		fac[i]=(long long)fac[i-1]*i%mo;
    		inv2[i]=(long long)inv2[i-1]*2%mo;
    	}
    	for (int i=0;i<=A*2;++i){
    		invf[i]=inv(fac[i]);
    		inv2[i]=inv(inv2[i]);
    	}
    	ans1[0]=ans2[0]=0;
    	for (int i=1;i<=A;++i){
    		ans1[i]=(ans1[i-1]+(long long)C(a[1]+i-2,i-1)*(i-1)%mo*inv2[a[1]+i-1]%mo)%mo;
    		ans2[i]=(ans2[i-1]+(long long)C(a[1]+i-2,i-1)*inv2[a[1]+i-1]%mo)%mo;
    		ans[i]=(ans1[i]+(long long)i*(1-ans2[i]+mo)%mo)%mo;
    	}
    	long long sum=a[1];
    	for (int i=2;i<=n;++i)
    		sum+=ans[a[i]];
    	printf("%lld
    ",sum%mo);
    	return 0;
    }
    

    总结

    期望的线性性真是奇妙啊……

  • 相关阅读:
    209. Minimum Size Subarray Sum
    208. Implement Trie (Prefix Tree)
    207. Course Schedule
    206. Reverse Linked List
    205. Isomorphic Strings
    204. Count Primes
    203. Remove Linked List Elements
    201. Bitwise AND of Numbers Range
    199. Binary Tree Right Side View
    ArcGIS API for JavaScript 4.2学习笔记[8] 2D与3D视图同步
  • 原文地址:https://www.cnblogs.com/jz-597/p/11483219.html
Copyright © 2011-2022 走看看