2018.9.1zrnoip模拟T2

描述
给出一个长度为 N 的数列 a。

进行若干轮操作,每次操作在 [1,N] 中等概率选择一个使得 ai>0 的 i,并将 ai 减少 1。

问,期望多少次操作后 a1 被减成了零。

输入格式
第一行一个整数 N。

第二行 N 个整数,第 i 个为 ai。

输出格式
一行一个整数,表示答案。为避免精度误差,答案对 323232323 取模。

即设答案化为最简分式后的形式为 a b ,其中 a 和 b 互质。输出整数 xx 使得 bx≡a(mod323232323) 且 0≤x<323232323。可以证明这样的整数 xx 是唯一的。

样例一
input
3
2 3 3
output
202020207
限制与约定
每个测试点 10 分,共 10 个测试点:
这里写图片描述
对于所有的数据,有:1≤N,1≤ai≤5×10^5。
时间限制:1s
空间限制:256MB


我们先考虑一个30分的暴力
dp
这应该很好写….
我们考虑正解
假如我们能把每个 a i 被选的期望个数求出来那么答案就很好算了:

a n s = i = 2 n f i + a 1

问题就在于 f i 怎么求
既然我们可以把问题独立出来,是否可以把求解 f i 给独立出来呢?
我们发现这个问题中唯一的规律就是 1 必定被拿 a 1
我们在结合 n <= 2 的部分分
我们是不是可以对于每个 a i ,都拿他和 a 1 算出 f i
我们思考一下,如果我们把操作序列中和 a 1 a i 无关的拿掉
那么相当于我们选取 a 1 a i 的概率都是 1 2
!!!
那我们就可以独立做了
但是这样分开dp只有60分
我们考虑怎么优化
我们把问题转化一下
题意相当于是我们从 ( a 1 , a i ) 出发,每次向下向右随机游走
走到坐标轴结束
走到 ( 0 , a ) 的贡献是 a i a ,走到 ( a , 0 ) 的贡献是 a i
于是我们可以列出 a i 的贡献式子:
i = 0 a i 1 i C a 1 1 + i i 2 a 1 + i + a i ( 1 i = 0 a i 1 C a 1 1 + i i 2 a 1 + i )

我们发现 a i 增加1的时候式子的转移是 O ( 1 )
于是就可以线性求解啦~

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x];i;i = e[i].n)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
const int p = 323232323;
int n;
int Max;
int a[501000] , bin[1001000] , fac[1001000] , Fac[1001000];
int f[501000] , suf[501000];
int ans[501000];
int read(){int sum = 0;char c = getchar();bool flag = true;while(c < '0' || c > '9') {if(c == '-') flag = false;c = getchar();}while(c >= '0' && c <= '9') sum = sum * 10 + c - 48,c = getchar();if(flag) return sum;else return -sum;}
int Pow(int a,int x){int sum = 1;while(x){if(x & 1) sum = 1ll * sum * a % p;a = 1ll * a * a % p;x >>= 1; }return sum;}
int C(int a,int b){if(b == 0) return 1;return 1ll*fac[a]%p*Fac[b]%p*Fac[a-b]%p;}
int main()
{
    n = read();rep(i,1,n) a[i] = read(),Max = max(Max,a[i]);
    bin[0] = 1;rep(i,1,2*Max) bin[i] = (bin[i-1]<<1)%p;
    rep(i,1,2*Max) bin[i] = Pow(bin[i],p-2);
    fac[0] = 1;rep(i,1,2*Max) fac[i] = 1ll * fac[i-1] * i % p;
    rep(i,1,2*Max) Fac[i] = Pow(fac[i],p-2);
    rep(i,0,Max) f[i] = 1ll * bin[a[1]+i] * C(a[1]+i-1,i)%p;
    rep(i,0,Max) suf[i] = (suf[i-1]+f[i])%p;
    ans[1] = (1-f[0]+p)%p;
    rep(i,2,Max)
    {
        ans[i] = ans[i-1];
        ans[i] = ans[i] + 1;
        ans[i] = ans[i] - suf[i-1];
        ans[i] = (ans[i]%p+p)%p;
    }
    int tot = a[1];
    rep(i,2,n) tot = (tot + ans[a[i]])%p;
    printf("%d\n",tot);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/82354965