【JZOJ4939】平均值 题解
題目大意
??給定一個長度為 nnn 的序列 a1,?,ana_1,\cdots,a_na1?,?,an?,求所有區間的 mexmexmex 平均值之和,即
∑l=1n∑r=lnmex(al,al+1,?,ar)r?l+1(mod998244353)\sum_{l=1}^n\sum_{r=l}^n \frac{mex(a_l,a_{l+1},\cdots,a_r)}{r-l+1} \pmod{998244353} l=1∑n?r=l∑n?r?l+1mex(al?,al+1?,?,ar?)?(mod998244353)
??1≤n≤5×105,0≤ai≤5×1051 \leq n \leq 5 \times 10^5,~~0 \leq a_i \leq 5 \times 10^51≤n≤5×105,??0≤ai?≤5×105
\\
\\
\\
題解
??這題大概是有兩種解法,官方題解是轉化成 ∑i=0max?{a}∑l≤r[mex(al,?,ar)≥i]r?l+1\sum_{i=0}^{\max\{a\}}\sum_{l \leq r} \frac{[mex(a_l,\cdots,a_r) \geq i]}{r-l+1}∑i=0max{a}?∑l≤r?r?l+1[mex(al?,?,ar?)≥i]? 來做,但它比較簡略我沒搞懂。于是又找到了HOWARLI的做法,我這個就是參考他的。被吊打啦
??有一種傳統建模是,左端點從右往左移動,用線段樹維護右端點的答案。但是在這題,左端點往左移相當于給若干個序列插入一個元素, mexmexmex 怎么變就很難搞了。
??但是變通一下,左端點從左往右移,就很好搞了。因為這對于 mexmexmex 來說相當于是區間取 min?\minmin 的操作。
??當左端點從 i?1i-1i?1 移到 iii,就相當于刪去 ai?1a_{i-1}ai?1?,假設 i?1i-1i?1 后面的第一個跟 ai?1a_{i-1}ai?1? 相同的元素是 anexti?1a_{next_{i-1}}anexti?1??,那么刪去 ai?1a_{i-1}ai?1? 影響到的右端點范圍就是 [i,nexti?1)[i,next_{i-1})[i,nexti?1?)。在這個范圍里所有 mexmexmex 值大于 ai?1a_{i-1}ai?1? 的都會變成 ai?1a_{i-1}ai?1?。
??由于 mexmexmex 是分段遞增的,我們在這個范圍內找到所有 mexmexmex 值大于 ai?1a_{i-1}ai?1? 的段,結算它們的貢獻,并更新它們。
??假設一個段 [l,r][l,r][l,r],mexmexmex 值為 mmm。對于里面的一個元素 x(x∈[l,r])x~(x \in [l,r])x?(x∈[l,r]),它最早在左端點為 ttt 時把 mexmexmex 值更新為 mmm,那么它要結算的貢獻就是 m(1x?t+1+?+1x?(i?1)+1)m(\frac{1}{x-t+1}+\cdots+\frac{1}{x-(i-1)+1})m(x?t+11?+?+x?(i?1)+11?),即 m(sx?t+1?sx?(i?1))m(s_{x-t+1}-s_{x-(i-1)})m(sx?t+1??sx?(i?1)?)(記 sn=∑i=1n1is_n=\sum_{i=1}^n \frac 1isn?=∑i=1n?i1?)。
??于是用線段樹維護一下 mexmexmex 的分段、區間 ∑sx?t+1\sum s_{x-t+1}∑sx?t+1? 即可。
??每次左端點的移動,最多新增 2 個段,刪除若干個段,因此段的總量也是 O(n)O(n)O(n) 的。時間復雜度 O(nlog?n)O(n \log n)O(nlogn)。
代碼
#include<cstdio> #include<cstring> #include<algorithm> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std;typedef long long LL;const int maxn=5e5+5; const LL mo=998244353;struct TR{int minmex,maxmex;LL st; };int n,a[maxn];LL Pow(LL x,LL y) {LL re=1;for(; y; y>>=1, x=x*x%mo) if (y&1) re=re*x%mo;return re; }int ap[maxn],nxt[maxn],init_mex[maxn]; LL s[maxn],ss[maxn]; void Pre() {fd(i,n,1){nxt[i]=(!ap[a[i]]) ?n+1 :ap[a[i]];ap[a[i]]=i;}memset(ap,0,sizeof(ap));int mex=0;fo(i,1,n){ap[a[i]]=1;while (ap[mex]) mex++;init_mex[i]=mex;}fo(i,1,n) s[i]=(s[i-1]+Pow(i,mo-2))%mo, ss[i]=(ss[i-1]+s[i])%mo; }TR tr[4*maxn]; pair<int,int> bz[4*maxn]; TR merge(const TR &a,const TR &b) {return (TR){min(a.minmex,b.minmex),max(a.maxmex,b.maxmex),(a.st+b.st)%mo}; } void update(int k,int t,int l,int mid,int r) {if (!bz[k].first) return;tr[t]=(TR){bz[k].second,bz[k].second,(ss[mid-bz[k].first+1]-ss[l-bz[k].first]+mo)%mo};tr[t+1]=(TR){bz[k].second,bz[k].second,(ss[r-bz[k].first+1]-ss[mid+1-bz[k].first]+mo)%mo};bz[t]=bz[t+1]=bz[k];bz[k]=make_pair(0,0); } void tr_js(int k,int l,int r) {if (l==r){tr[k]=(TR){init_mex[r],init_mex[r],s[r]};return;}int t=k<<1, mid=(l+r)>>1;tr_js(t,l,mid), tr_js(t+1,mid+1,r);tr[k]=merge(tr[t],tr[t+1]); } pair<int,int> cx_bs(int k,int l,int r,int x,int z) {if (l==r) return (tr[k].maxmex>z) ?make_pair(l,tr[k].maxmex) :make_pair(-1,-1) ;int t=k<<1, mid=(l+r)>>1;update(k,t,l,mid,r);return (x<=mid && tr[t].maxmex>z) ?cx_bs(t,l,mid,x,z) :cx_bs(t+1,mid+1,r,x,z); } int cx_r(int k,int l,int r,int x,int z) {if (l==r) return l;int t=k<<1, mid=(l+r)>>1;update(k,t,l,mid,r);return (x<=mid && tr[t+1].minmex>z) ?cx_r(t,l,mid,x,z) :cx_r(t+1,mid+1,r,x,z); } LL cx_st(int k,int l,int r,int x,int y) {if (x<=l && r<=y) return tr[k].st;int t=k<<1, mid=(l+r)>>1;update(k,t,l,mid,r);LL re=0;if (x<=mid) re=cx_st(t,l,mid,x,y);if (mid<y) (re+=cx_st(t+1,mid+1,r,x,y))%=mo;return re; } void tr_xg(int k,int l,int r,int x,int y,pair<int,int> z) {if (x<=l && r<=y){tr[k]=(TR){z.second,z.second,(ss[r-z.first+1]-ss[l-z.first]+mo)%mo};bz[k]=z;return;}int t=k<<1, mid=(l+r)>>1;update(k,t,l,mid,r);if (x<=mid) tr_xg(t,l,mid,x,y,z);if (mid<y) tr_xg(t+1,mid+1,r,x,y,z);tr[k]=merge(tr[t],tr[t+1]); }int main() {freopen("average.in","r",stdin);freopen("average.out","w",stdout);scanf("%d",&n);fo(i,1,n) scanf("%d",&a[i]);Pre();tr_js(1,1,n);LL ans=0;fo(i,1,n){if (i>1){for(int l=i, r; l<nxt[i-1]; l=r+1){pair<int,int> t=cx_bs(1,1,n,l,a[i-1]);l=t.first;if (l==-1 || l>=nxt[i-1]) break;r=min(cx_r(1,1,n,l,t.second),nxt[i-1]-1);(ans+=(cx_st(1,1,n,l,r)-ss[r-(i-1)]+mo+ss[l-(i-1)-1])%mo*t.second)%=mo;tr_xg(1,1,n,l,r,make_pair(i,a[i-1]));}}(ans+=cx_st(1,1,n,i,i)*(a[i]==0))%=mo;}printf("%lld\n",ans); }總結
以上是生活随笔為你收集整理的【JZOJ4939】平均值 题解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 华为系统鸿蒙适配机型,华为鸿蒙2.0升级
- 下一篇: AXIOM 读写 xml文件