• 07-25 考试


    十分困倦而sb的一天。

    期望得分:100+100+0

    实际得分:100+10+0

     

    A. 匹配

    一开始看题,前缀后缀最长匹配?kmp!

    然后再看,hash就完事了,好打还复杂度低。

    一会瞎推了下码完,后来因为T3没思路还来写了个对拍。发现暴力比正解快,然后看到输出的 0 0 0 0... 然后就懂了233。

    PS:居然拍出了一组答案1w多的数据,欧皇ha

    正解:KMP 在A串求next[],然后跑B串,最后的匹配长度就是ans

    或者。。。  hash nb! 直接$O(n)$

     

    B. 回家

    下次看到“我认为的”水题,一定一定一定要要要验证验证验证正确性正确性正确性!

    这题我打个了Tarjan 判割点判连通然后就撂了

    hack数据:

    1

    5 5

    1 5

    1 2

    5 2

    2 3

    3 4

    正解:必过点一定是割点,而割点不一定是必过点。如以上数据,既然都到了5了还往下走个**啊

    于是我们要给必过点一个严谨的定义:

    必过点,就是去掉了就一定不能达到目的地。换言之就是去掉该点,1点与n点不连通 断开分属于两个连通块。

    解法一:

    点双里的点不符合必过点的定义,然后我们就缩个点把它干掉,建出圆方树。

    然后根据定义我们可以这样找,把1作为根,如果n点在该点且该点非1/n点的子树里,则该点是必过点。

    证明:树上的两点间有且仅有一条简单路径,n点的祖先都是1到n点圆方树上的的简单路径上的点,去掉任何一个都会使1 n不连通,符合必过点定义,得证。

    接下来就可以dfs搞定了。

    解法二:

    我们可以不建出圆方树,因为Tarjan时就有搜索树结构,类似于BLO那题,我们只要特判反祖就可以了。

    if(dfn[u]<=low[v]&&dfn[v]<=dfn[n])

    只要在判割点时多加一句话,然后就可以AC。

    我们来证明下它的正确性:

    首先第一个判断,保证了这个儿子的子树不存在反祖,我们就可以按照树来处理。  可以通过上面hack数据来看这个判断的作用。

    第二个判断,保证了n在v的子树里,同时==考虑了v就是n的情况,以下是对于判断二的证明:

    分类讨论下:  以下n树代表的是含有n的子树,而非n的子树

    1.先v树后n树,dfn[n]还未更新,条件不成立

    2.v树即是n树,a.  v!=n 知v先赋dfn,n后赋  成立

           b.  v==n dfn[v]==dfn[n]    成立

    3.先n树后v树,即访问顺序为先n后v,则dfn[v]>dfn[n]      不成立

    得证。

    我们再来证另一种相似写法的错误性:

    if(dfn[u]<=low[v]&&dfn[u]<dfn[n])

    假设一个非根结点u有两个搜索树儿子,一个儿子h无返祖,另一个儿子g的子树含有n且返祖,u节点的父亲节点为f。

              

    如果从u第一次进入的是g,则会更新dfn[n],此时条件一不满足,条件二满足

    第二次进入h,此时条件一满足,条件二元素不变,依然满足  同时满足判定u为必过点

    但显然u在点双中,不符,得证。

    C. 寿司

    考试的时候想到了断环成链,枚举特殊点,但并没有想到向区间两边分别集中这种较容易处理的计算方法(我想往区间中央集中,然后不会算),实际上这是tm的等效的啊!R到中央B不就到**的两边了嘛,正难则反啊!我*$%&^#$^%$

    然后我就puts("0");了。。。

    说几种思路:

    $O(n^2)$ 枚举区间,枚举断点,从断点为分水岭向两侧集中颜色,预处理出贡献即可。

    $O(nlog_{1.5}n)$ gmk考场上想出来的。我们发现对于同一个区间,ans关于断点位置呈单峰函数状(U),然后我们可以外侧枚举区间,对于同一个区间用三分找谷底,最后对所有区间的ans最小值取min。

    $O(nlog_2 n)$ 转网上题解的话:显然,这样做的答案,应该是,每一个被移到左边去的R左边原来的B的个数,每一个被移到右边去的R右边原来的B的个数,那么很显然的,我们最好的方式是将,第(B的总个数 + 1) / 2个B(以下将第(B的总个数 + 1) / 2个B的位置简称为pos)左边的R全部移到左边,右边的R移到右边。

    虽然我并不觉得显然。。。  然后就可以二分那个pos,使左边的B个数贴近cnt_B/2

    不难发现二分的是决策点(再带入计算)而三分的是ans

    $O(n)$ 我们通过三分和二分 发现决策点j是不会左移的,严谨的证明wd已给出。 然后我们就不用二分决策点j了,用单调指针j直接扫即可。

    关于计算:

    wd大神给出了等差数列和位置求和,其做法的原因是各个点的贡献呈阶梯状(脑补脑补)。

    我们不妨直接处理出所有R点的阶梯前缀答案,然后发现区间外的贡献对所有R点来说是可以计算的(一整块),然后做差就可以求出[l,r]区间内的贡献了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<algorithm>
     5 #define int long long
     6 #define reg register
     7 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
     8 using namespace std;
     9 inline int read();
    10 const int LEN=2000005;
    11 char s[LEN];
    12 int sl[LEN],sr[LEN],bl[LEN],rl[LEN],br[LEN],rr[LEN];
    13 int len;
    14 int calcl(int l,int r)
    15 {
    16     return sl[r]-sl[l-1]-bl[l-1]*(rl[r]-rl[l-1]);
    17 }
    18 int calcr(int l,int r)
    19 {
    20     return sr[l]-sr[r+1]-br[r+1]*(rr[l]-rr[r+1]);
    21 }
    22 int calc(int l,int m,int r)
    23 {
    24     return calcl(l,m)+calcr(m+1,r);
    25 }
    26 int sf(int l,int r)
    27 {
    28 //    printf("L=%lld R=%lld
    ",l,r);
    29     int ml,mr,L=l,R=r;
    30     while(r-l>2)
    31     {
    32         ml=(r-l+1)/3+l;
    33         mr=(r-l+1)*2/3+l;
    34         if(calc(L,ml,R)>calc(L,mr,R)) l=ml;
    35         else r=mr;
    36     }
    37     return min(calc(L,l,R),min(calc(L,l+1,R),calc(L,r,R)));
    38 }
    39 signed main()
    40 {
    41     int T=read();
    42     while(T--)
    43     {
    44         scanf("%s",s+1);
    45         len=strlen(s+1);
    46         int lim=len<<1;
    47         F(i,len+1,lim) s[i]=s[i-len];
    48         F(i,1,lim)
    49         {
    50             sl[i]=sl[i-1];
    51             bl[i]=bl[i-1];
    52             rl[i]=rl[i-1];
    53             if(s[i]=='B') ++bl[i];
    54             else
    55             {
    56                 sl[i]+=bl[i];
    57                 ++rl[i];
    58             }
    59 //            printf("i=%d %c %d %d %d
    ",i,s[i],sl[i],bl[i],rl[i]);
    60         }
    61         for(reg int i=lim;i>=1;--i)
    62         {
    63             sr[i]=sr[i+1];
    64             br[i]=br[i+1];
    65             rr[i]=rr[i+1];
    66             if(s[i]=='B') ++br[i];
    67             else
    68             {
    69                 sr[i]+=br[i];
    70                 ++rr[i];
    71             }
    72         }
    73         int ans=0x3f3f3f3f3f3f3f3f;
    74         F(i,1,len) ans=min(ans,sf(i,i+len-1));
    75         printf("%lld
    ",ans);
    76     }
    77     return 0;
    78 }
    79 inline int read()
    80 {
    81     int x=0;
    82     char tc=getchar();
    83     while(tc<'0'||tc>'9') tc=getchar();
    84     while(tc>='0'&&tc<='9')
    85     {
    86         x=x*10+tc-48;
    87         tc=getchar();
    88     }
    89     return x;
    90 }
    三分
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<algorithm>
     5 #define int long long
     6 #define reg register
     7 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
     8 using namespace std;
     9 inline int read();
    10 const int LEN=2000005;
    11 char s[LEN];
    12 int sl[LEN],sr[LEN],bl[LEN],rl[LEN],br[LEN],rr[LEN];
    13 int len;
    14 int calcl(int l,int r)
    15 {
    16     return sl[r]-sl[l-1]-bl[l-1]*(rl[r]-rl[l-1]);
    17 }
    18 int calcr(int l,int r)
    19 {
    20     return sr[l]-sr[r+1]-br[r+1]*(rr[l]-rr[r+1]);
    21 }
    22 int calc(int l,int m,int r)
    23 {
    24     return min(calcl(l,m)+calcr(m+1,r),calcl(l,m-1)+calcr(m,r));
    25 }
    26 signed main()
    27 {
    28     int T=read();
    29     while(T--)
    30     {
    31         scanf("%s",s+1);
    32         len=strlen(s+1);
    33         int lim=len<<1;
    34         F(i,len+1,lim) s[i]=s[i-len];
    35         F(i,1,lim)
    36         {
    37             sl[i]=sl[i-1];
    38             bl[i]=bl[i-1];
    39             rl[i]=rl[i-1];
    40             if(s[i]=='B') ++bl[i];
    41             else
    42             {
    43                 sl[i]+=bl[i];
    44                 ++rl[i];
    45             }
    46         }
    47         for(reg int i=lim;i>=1;--i)
    48         {
    49             sr[i]=sr[i+1];
    50             br[i]=br[i+1];
    51             rr[i]=rr[i+1];
    52             if(s[i]=='B') ++br[i];
    53             else
    54             {
    55                 sr[i]+=br[i];
    56                 ++rr[i];
    57             }
    58         }
    59         int l,j=10,r;
    60         int ans=0x3f3f3f3f3f3f3f3f;
    61         F(i,1,len)
    62         {
    63             l=i; r=len+i-1;
    64 /*            F(i,1,lim)
    65             {
    66                 if(i==l) putchar('[');
    67                 printf("%c",s[i]);
    68                 if(i==r) putchar(']');
    69             }
    70             puts("");
    71             printf("cal=%lld
    ",calc(l,10,r));*/
    72             if(j<i) ++j;
    73             while(calc(l,j,r)>=calc(l,j+1,r))
    74             {
    75                 ++j;
    76             }
    77 //            printf("l=%lld j=%lld r=%lld c=%lld->%lld
    ",l,j,r,calc(l,j,r),calc(l,j+1,r));
    78             ans=min(ans,calc(l,j,r));
    79         }
    80         printf("%lld
    ",ans);
    81     }
    82     return 0;
    83 }
    84 inline int read()
    85 {
    86     int x=0;
    87     char tc=getchar();
    88     while(tc<'0'||tc>'9') tc=getchar();
    89     while(tc>='0'&&tc<='9')
    90     {
    91         x=x*10+tc-48;
    92         tc=getchar();
    93     }
    94     return x;
    95 }
    O(n)
  • 相关阅读:
    【tyvj1952】easy
    【noip2005】篝火晚会
    BZOJ4818: [Sdoi2017]序列计数
    BZOJ2436: [Noi2011]Noi嘉年华
    BZOJ4826: [Hnoi2017]影魔
    BZOJ4540: [Hnoi2016]序列
    BZOJ4827: [Hnoi2017]礼物
    BZOJ3527: [Zjoi2014]力
    BZOJ4407: 于神之怒加强版
    BZOJ1854: [Scoi2010]游戏
  • 原文地址:https://www.cnblogs.com/hzoi-yzh/p/11247205.html
Copyright © 2020-2023  润新知