【2019北京集訓測試賽(十三)】數據(sj) 冷靜分析

題目大意:給你一個表明區間$[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 }

相關文章
相關標籤/搜索