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\n",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\n",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\n",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\n",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\n",l,j,r,calc(l,j,r),calc(l,j+1,r));
78             ans=min(ans,calc(l,j,r));
79         }
80         printf("%lld\n",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)

 

posted @ 2019-07-26 08:14  hzoi_yzh  阅读(154)  评论(0编辑  收藏  举报