ABC276F
[[Segment Tree]] [[Expectation]]
My Sol.
先是我的做法
把max函数拆掉:\(\max\{x,y\}=\frac{1}{2}*(x+y+|x-y|)\)
然后我们的 \(x\) 和 \(y\) 是在同一个序列 \(A\) 里取的
所以转化一下答案
\(\mathbb{E}(\max\{x,y\})=\bar{A}+\frac{\sum_{i=1}^n\sum_{j=i+1}^n|a_i-a_j|}{n^2}\)
所以可以令 \(A\) 有序,式子化为:
\(\mathbb{E}(\max\{x,y\})=\bar{A}+\sum_{i=1}^n\frac{cnt(1\to a_{i-1})*a_i-sum(1\to a_{i-1})+sum(a_{i+1}\to ma)-cnt(a_{i+1}\to ma)*a_i}{n^2}\)
分母上面的式子可以用数据结构维护,我写了个线段树
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200005,mod=998244353;
int n;
using ll=long long;
ll pw(ll x,int a=mod-2){
ll ret=1ll;
for(;a;a>>=1){
if(a&1)ret=ret*x%mod;
x=x*x%mod;
}
return ret;
}
struct T{
ll sum,cnt;
T operator+(const T&a){
return T{(sum+a.sum)%mod,cnt+a.cnt};
}
}_[N<<2];
ll a[N],an,aan,ma;
#define ls (p<<1)
#define rs (p<<1|1)
int x,y;
void add(int l,int r,int p){
if(l==r){
_[p]=_[p]+T{l,1};
return;
}
int m=l+r>>1;
if(x<=m)add(l,m,ls);
else add(m+1,r,rs);
_[p]=_[ls]+_[rs];
}
T qry(int l,int r,int p){
T ret={0ll,0ll};
if(l>r||l>y||r<x)return ret;
if(x<=l&&r<=y)return _[p];
int m=l+r>>1;
if(x<=m)ret=ret+qry(l,m,ls);
if(y>m)ret=ret+qry(m+1,r,rs);
return ret;
}
T s1,s2,s3;
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++)scanf("%lld",a+i),ma=max(a[i],ma);ma++;
for(int i=1;i<=n;i++){
(aan+=a[i])%=mod;
x=1,y=a[i]-1;s1=qry(1,ma,1);
x=a[i]+1,y=ma;s2=qry(1,ma,1);
x=a[i],y=a[i];s3=qry(1,ma,1);
(an+=((s1.cnt*a[i]%mod-s1.sum+mod)%mod+(s2.sum-s2.cnt*a[i]%mod+mod)%mod)%mod)%=mod;
x=a[i];add(1,ma,1);
printf("%lld\n",(an*pw(i*i%mod)%mod+aan*pw(i)%mod)%mod);
}
}
我之前的模数会撞segment tree里的p,以后要注意
因为 \(i*i\) 会爆int,调了40min没调出来
我成了一个坚定的#define int long long主义者
Another Sol.
我们不化式子
考虑算出加这个数对上次期望的影响
加一个数,就相当于样本空间里多了 \(i\) 项
我们只要算出这个多出的贡献和
它只会对值小于 \(a_i\) 的点产生影响,所以就是求一个\(cnt(1\to a_{i-1})*a_i+sum(a_{1+1}\to ma)\)就行了
下面是QY的赛时代码:
# include <bits/stdc++.h>
# define int long long
# define wheneveright signed main
# define pii pair < int, int >
# define mp make_pair
# define x first
# define y second
using namespace std;
const int maxn = 200005;
const int N = 200000;
const int mod = 998244353;
void Add (pii & A, pii B) { A.x += B.x; A.y += B.y; return ; }
int inv (int x, int y = mod - 2) {
int ret = 1;
while (y) {
if (y & 1) ret = ret * x % mod;
x = x * x % mod; y >>= 1;
}
return ret % mod;
}
struct reader {
template <typename Type>
reader & operator >> (Type & ret) {
int f = 1; ret = 0; char ch = getchar ();
for (;!isdigit (ch); ch = getchar ()) if (ch == '-') f = -f;
for (; isdigit (ch); ch = getchar ()) ret = (ret * 10) + ch - '0';
ret *= f; return * this;
}
} fin;
# define ls(id) ((id) << 1)
# define rs(id) ((id) << 1 | 1)
int val[maxn << 2], sum[maxn << 2];
void push_up (int id) {
val[id] = val[ls (id)] + val[rs (id)];
sum[id] = sum[ls (id)] + sum[rs (id)];
return ;
}
void update (int id, int l, int r, int pos, int k) {
if (l == pos && pos == r) {
sum[id] += k * pos;
val[id] += k;
return void ();
}
int mid = (l + r) >> 1;
if (pos <= mid) update (ls (id), l, mid, pos, k);
else update (rs (id), mid + 1, r, pos, k);
return push_up (id);
}
int find_mid (int id, int l, int r, int rk) {
if (l == r) return l;
int mid = (l + r) >> 1;
if (rk <= val[ls (id)]) return find_mid (ls (id), l, mid, rk);
return find_mid (rs (id), mid + 1, r, rk - val[ls (id)]);
}
pii query (int id, int l, int r, int L, int R) {
if (L > R) return mp (0ll, 0ll);
if (L <= l && r <= R) return mp (val[id], sum[id]);
int mid = (l + r) >> 1; pii ret = mp (0ll, 0ll);
if (L <= mid) Add (ret, query (ls (id), l, mid, L, R));
if (mid < R) Add (ret, query (rs (id), mid + 1, r, L, R));
return ret;
}
# undef ls
# undef rs
int n, p, now;
wheneveright () {
freopen("1.in","r",stdin);
freopen("std.out","w",stdout);
fin >> n; now = 0;
for (int i = 1; i <= n; i++) {
fin >> p;
now = (now + p) % mod;
pii L = query (1, 1, N, 1, p);
pii R = query (1, 1, N, p + 1, N);
now = (now + p * L.x * 2 % mod) % mod;
now = (now + R.y * 2 % mod) % mod;
printf ("%lld\n", (now * inv (i * i % mod)) % mod);
update (1, 1, N, p, 1);
}
return 0;
}
可以看出我的写法大大复杂化了

浙公网安备 33010602011771号