描述
给出一个长度为 N 的数列 a。
进行若干轮操作,每次操作在 [1,N] 中等概率选择一个使得 ai>0 的 i,并将 ai 减少 1。
问,期望多少次操作后 a1 被减成了零。
输入格式
第一行一个整数 N。
第二行 N 个整数,第 i 个为 ai。
输出格式
一行一个整数,表示答案。为避免精度误差,答案对 323232323 取模。
即设答案化为最简分式后的形式为 ,其中 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
这应该很好写….
我们考虑正解
假如我们能把每个
被选的期望个数求出来那么答案就很好算了:
问题就在于 怎么求
既然我们可以把问题独立出来,是否可以把求解 给独立出来呢?
我们发现这个问题中唯一的规律就是 必定被拿 次
我们在结合 的部分分
我们是不是可以对于每个 ,都拿他和 算出
我们思考一下,如果我们把操作序列中和 和 无关的拿掉
那么相当于我们选取 和 的概率都是
!!!
那我们就可以独立做了
但是这样分开dp只有60分
我们考虑怎么优化
我们把问题转化一下
题意相当于是我们从 出发,每次向下向右随机游走
走到坐标轴结束
走到 的贡献是 ,走到 的贡献是
于是我们可以列出 的贡献式子:
我们发现 增加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;
}