题目描述
$Cab$有两行石子,每个石子上有一个字母,为$'C''A''B'$中的一个。
一开始,在每行第一个石子上站着一只$lucky$,$Cab$每次可以选择一个字母,使得所站石子上字母为该字母的$lucky$向前走一步,如果此时$lucky$已经到了一行石子的结尾就会掉出去,$Cab$显然不会这么做。
一个数对$(x,y)$是$lucky$的,当且仅当在$lucky$不掉出去的前提下,通过一些操作能使第一行的$lucky$处于第$x$个石子的同时第二只$lucky$处于第$y$个石子。
请求出有多少个$lucky$的数对。
输入格式
第一行一个长度为$n$的字符串表示第一行石子。
第二行一个长度为$m$的字符串表示第二行石子。
输出格式
输出一个答案表示$lucky$的数对个数。
样例
样例输入:
CAB
ABCAB
样例输出:
11
数据范围与提示
对于$30\%$的数据:$n\leqslant 1,000,m\leqslant 1,000$。
对于另$30\%$的数据:$n\leqslant 50,000,m\leqslant 50,000$,且两个字符串中只含有两种字母。
对于$100\%$的数据:$n\leqslant 1,000,000,m\leqslant 1,000,000$。
题解
官方题解画了一堆图,我也没看懂。
对于第一个串中的每一个点,其有一个覆盖范围$(l,r)$,可以用贪心的思想,$l$即为尽可能让其不动;$r$则为尽可能让它动;注意边界即可。
但是打个表会发现,这中间有一些点还是不能取到;再认真看一下,会发现对于当前点$a_i$,如果$a_i=b_j$且$a_{i-1}=b_{j+1}$,那么这个$(i,j)$是不可取的。
那么答案就是:
$$ans=\sum \limits_{i=1}^n r_i-l_i+1-num[i]$$
上式中的$num[i]$即为$l_i\sim r_i$中$a_i=b_j$且$a_{i-1}=b_{j+1}$的个数。
$num$数组可以用桶$+$前缀和$+$差分处理。
如果你发现$WA90$的话可以考虑将两个串的读入顺序交换即可。
时间复杂度:$\Theta(n+m)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h> using namespace std; int a[1000001],b[1000001],la,lb; char ch1[1000001],ch2[1000001]; int l[1000001],r[1000001]; int t[1000001][6]; long long ans; int main() { scanf("%s%s",ch1+1,ch2+1); la=strlen(ch2+1); lb=strlen(ch1+1); for(int i=1;i<=la;i++) a[i]=ch2[i]-'A'+1; for(int i=1;i<=lb;i++) b[i]=ch1[i]-'A'+1; int faill=1,failr=1; for(int i=1;i<=la;i++) { while(a[i]!=b[failr]&&failr<lb)failr++; l[i]=faill;r[i]=failr; if(a[i]==b[faill]&&faill<lb)faill++; if(failr<lb)failr++; } for(int i=2;i<=lb;i++) { if(b[i-1]==1&&b[i]==2)t[i][0]++; if(b[i-1]==2&&b[i]==1)t[i][1]++; if(b[i-1]==1&&b[i]==3)t[i][2]++; if(b[i-1]==3&&b[i]==1)t[i][3]++; if(b[i-1]==2&&b[i]==3)t[i][4]++; if(b[i-1]==3&&b[i]==2)t[i][5]++; t[i][0]+=t[i-1][0]; t[i][1]+=t[i-1][1]; t[i][2]+=t[i-1][2]; t[i][3]+=t[i-1][3]; t[i][4]+=t[i-1][4]; t[i][5]+=t[i-1][5]; } ans=r[1]-l[1]+1; for(int i=2;i<=la;i++) { ans+=r[i]-l[i]+1; if(a[i]==a[i-1])continue; if(a[i]==1&&a[i-1]==2)ans-=t[r[i]][0]-t[l[i]-1][0]; if(a[i]==2&&a[i-1]==1)ans-=t[r[i]][1]-t[l[i]-1][1]; if(a[i]==1&&a[i-1]==3)ans-=t[r[i]][2]-t[l[i]-1][2]; if(a[i]==3&&a[i-1]==1)ans-=t[r[i]][3]-t[l[i]-1][3]; if(a[i]==2&&a[i-1]==3)ans-=t[r[i]][4]-t[l[i]-1][4]; if(a[i]==3&&a[i-1]==2)ans-=t[r[i]][5]-t[l[i]-1][5]; } printf("%lld",ans); return 0; }
rp++