zoukankan      html  css  js  c++  java
  • 【2019北京集训测试赛(十三)】数据(sj) 冷静分析

    题目大意:给你一个代表区间$[1,n]$的线段树,问你随机访问区间$[1,n]$中的一个子区间,覆盖到的线段树节点个数的期望(需要乘上$frac{n(n-1)}{2}$后输出)。

    数据范围:$n≤10^{18}$

    貌似各位的做法都非常优秀,代码也非常短,那么我来讲一个垃圾做法:

    我们设$f[i]$表示一个构建出$[1,i]$的线段树,随机访问一个子区间覆盖线段树节点个数的期望(为方便处理,乘上了$frac{i(i-1)}{2}$)。

    显然$f[n]$就是答案。

    我们再设$fl[j][i]$表示一棵$[1,i]$的线段树,从左边往右,覆盖了$j$个线段树节点的方案数。

    同理我们处理出$fr[j][i]$

    我们发现:当$j>1$时,选择覆盖$j$个点,这$j$个点显然不会包含整个区间。

    我们设$L=lceil frac{i}{2} ceil$ ,$R=lfloor frac{i}{2} floor $

    那么有$fl[i][j]=fl[j][L]+fl[j-1][r]-[j≤2],fr[i][j]$同理。

    我们考虑$f[i]$要怎么求。

    不难发现,$f[i]$有四种构成方式:只选择了左/右端的区间,两边都选了,恰好选择了根节点。

    只选择一侧的显然是$f[L]+f[R]$,恰好选择根节点的贡献显然为$1$。

    对于两边都选的情况,我们通过枚举$fr[][L]$和$fl[][R]$,简单地乘起来,再乘上总共选择的节点个数,就可以了。

    综上,则有:

    $f[i]=1+f[L]+f[R]+sumlimits_{v_1=1}^{dep_1}sumlimits_{v_2=1}^{dep_2} (v_1+v_2) imesigg(fr[v_1][L] imes fl[v_2][R]-[v1=1,v2=1]igg)$

    其中,$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 }
    
    
  • 相关阅读:
    好久没更新
    基于slick grid做infinite scroll(2)
    基于slick grid做infinite scroll(1)
    用REST访问ALM的Servlet
    Angularjs中provider,factory和service的不同
    粗糙版斗破苍穹网络阅读器
    将斗破苍穹按章分隔
    实战第一个云程序
    js变量提升
    Thread
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10740203.html
Copyright © 2011-2022 走看看