題目大意:給你一個表明區間$[1,n]$的線段樹,問你隨機訪問區間$[1,n]$中的一個子區間,覆蓋到的線段樹節點個數的指望(須要乘上$\frac{n(n-1)}{2}$後輸出)。c++
數據範圍:$n≤10^{18}$spa
貌似各位的作法都很是優秀,代碼也很是短,那麼我來說一個垃圾作法:code
咱們設$f[i]$表示一個構建出$[1,i]$的線段樹,隨機訪問一個子區間覆蓋線段樹節點個數的指望(爲方便處理,乘上了$\frac{i(i-1)}{2}$)。blog
顯然$f[n]$就是答案。遞歸
咱們再設$fl[j][i]$表示一棵$[1,i]$的線段樹,從左邊往右,覆蓋了$j$個線段樹節點的方案數。ci
同理咱們處理出$fr[j][i]$it
咱們發現:當$j>1$時,選擇覆蓋$j$個點,這$j$個點顯然不會包含整個區間。class
咱們設$L=\lceil \frac{i}{2}\rceil$ ,$R=\lfloor \frac{i}{2} \rfloor $map
那麼有$fl[i][j]=fl[j][L]+fl[j-1][r]-[j≤2],fr[i][j]$同理。im
咱們考慮$f[i]$要怎麼求。
不難發現,$f[i]$有四種構成方式:只選擇了左/右端的區間,兩邊都選了,剛好選擇了根節點。
只選擇一側的顯然是$f[L]+f[R]$,剛好選擇根節點的貢獻顯然爲$1$。
對於兩邊都選的狀況,咱們經過枚舉$fr[][L]$和$fl[][R]$,簡單地乘起來,再乘上總共選擇的節點個數,就能夠了。
綜上,則有:
$f[i]=1+f[L]+f[R]+\sum\limits_{v_1=1}^{dep_1}\sum\limits_{v_2=1}^{dep_2} (v_1+v_2)\times\bigg(fr[v_1][L]\times fl[v_2][R]-[v1=1,v2=1]\bigg)$
其中,$dep1$,$dep2$表示左右兩顆子樹的最大深度。
在求解過程當中,咱們暴力往下遞歸,咱們須要特判$i=1,2,3$的狀況,而後就能夠了。
這個複雜度比較垃圾,應該是$O(log^3\ n)$的。
場上真刺激,最後十分鐘調處來了23333
1 #include<bits/stdc++.h> 2 #define M 998244353 3 #define L long long 4 #define MOD 998244353 5 using namespace std; 6 7 map<L,L> f,fl[100],fr[100],vis,up; 8 9 void solve(L i){ 10 if(vis[i]) return; 11 if(i==1){ 12 f[i]=fl[1][i]=fr[1][i]=vis[i]=1; 13 fl[0][i]=fr[0][i]=up[i]=1; 14 return; 15 } 16 if(i==2){ 17 f[i]=3; 18 fl[1][i]=fr[1][i]=2; 19 fl[0][i]=fr[0][i]=1; 20 vis[i]=up[i]=1; 21 return; 22 } 23 if(i==3){ 24 f[i]=7; 25 fl[1][i]=3; fr[1][i]=2; 26 fl[0][i]=fr[0][i]=1; 27 vis[i]=1; up[i]=2; 28 fr[2][i]=1; 29 return; 30 } 31 L l=(i+1)>>1,r=i-l; 32 solve(l); solve(r); 33 int upl=up[l],upr=up[r],UP=max(upl,upr)+1; up[i]=UP; 34 vis[i]=1; 35 L sum=f[l]+f[r]; 36 for(int v1=1;v1<=upl;v1++) 37 for(int v2=1;v2<=upr;v2++){ 38 sum=(sum+1LL*(v1+v2)*(fr[v1][l]*fl[v2][r]%MOD+MOD-(v1==1&&v2==1)))%MOD; 39 } 40 // for(int v1=0;v1<=upl;v1++) sum=(sum-fr[v1][l])%MOD; 41 // for(int v2=0;v2<=upr;v2++) sum=(sum-fl[v2][r])%MOD; 42 f[i]=(sum+1)%MOD; 43 for(int j=1;j<=UP;j++){ 44 fl[j][i]=(fl[j][l]+fl[j-1][r]-(j<=2)+MOD)%MOD; 45 int x=fl[j][i]; 46 fr[j][i]=(fr[j-1][l]+fr[j][r]-(j<=2)+MOD)%MOD; 47 int y=fr[j][i]; 48 x++; 49 } 50 // cout<<fr[2][3]<<endl; 51 fl[0][i]=fr[0][i]=1; 52 fl[1][i]++; fr[1][i]++; 53 } 54 55 int main(){ 56 L n;cin>>n; 57 solve(n); 58 cout<<f[n]<<endl; 59 }