正题
题目链接:https://www.luogu.com.cn/problem/P6834?contestId=34123
题目大意
nnn个点,每个点i(i≠1)i(i\neq 1)i(i=1)随机连接[i−k,i−1][i-k,i-1][i−k,i−1]中的一个点。对于每个点有一个权值aia_iai。每次可以选择一个全部都是正权值的连通块里所有权值减一,求最优期望次数。
解题思路
考虑每个点的贡献,对于一个节点xxx和它的父节点fafafa显然根据铺设道路那题的做法,这个点的贡献就是max{ax−afa,0}max\{a_x-a_{fa},0\}max{ax−afa,0}
所以我们需要维护一个数据结构可以查询比axa_xax小的数的和,支持插入删除。显然离散化之后用树状数组即可。
时间复杂度O(nlogn)O(n\log n)O(nlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
#define ll long long
using namespace std;
const ll N=1e6+10,XJQ=998244353;
ll n,k,num,answer,cnt;
ll inv[N],a[N],b[N],t[N],z[N];
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%XJQ;x=x*x%XJQ;b>>=1;}return ans;
}
void Change(ll x,ll val,ll flag){while(x<=cnt){t[x]=(t[x]+val)%XJQ;z[x]=z[x]+flag;x+=lowbit(x);}return;
}
ll Ask(ll x){ll ans=0;num=0;while(x){num=num+z[x];ans=(ans+t[x])%XJQ;x-=lowbit(x);}return ans;
}
int main()
{scanf("%lld%lld",&n,&k);inv[1]=1;for(ll i=2;i<=k;i++)inv[i]=XJQ-XJQ/i*inv[XJQ%i]%XJQ;for(ll i=1;i<=n;i++)scanf("%lld",&a[i]),b[++cnt]=a[i];sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;ll l=1,sum=0;answer=a[1];for(ll i=1;i<=n;i++){while(l<=n&&l<i-k){ll y=lower_bound(b+1,b+1+cnt,a[l])-b;Change(y,-a[l],-1);l++;}ll x=lower_bound(b+1,b+1+cnt,a[i])-b;ll w=Ask(x),ans=0;ans=(num*a[i]%XJQ-w+XJQ)%XJQ;answer=(answer+ans*inv[min(i-1,k)]%XJQ)%XJQ;Change(x,a[i],1);}printf("%lld",answer);
}