昨晚CF比赛比较颓,今天有心情写题解就不错了QWQ

洛谷题目页面传送门 & CodeForces题目页面传送门

给定字符串\(a,b,|a|=n,|b|=m\),求是否可以在\(a\)中选\(2\)个长度为\(s\)的不相交子串,使得\(b\)是这\(2\)个串按在\(a\)中的顺序连起来后得到的串的子串,若可以,输出任一选法。

\(2\le m\le 2s\le n\le 5\times 10^5\)。

设从\(a\)中选出的\(2\)个子串为\(a1,a2\)。分\(2\)种情况:

  1. \(a1\)或\(a2\)完全包含\(b\);
  2. \(a1\)的一个后缀与\(a2\)的一个前缀组成\(b\)。

第\(1\)种情况比较容易,直接将\(b\)作为模式串匹配\(a\)(这里我用的是Z算法(如果聪明的读者还不知道Z算法是什么,please点击这个)),匹配成功的位置再分\(2\)种情况:\(a1\)包含\(b\)和\(a2\)包含\(b\)。\(a1\)包含\(b\)的情况考虑贪心地将\(a1\)最左化,好给\(a2\)留位置,最后如果放得下直接输出答案return 0;;\(a2\)包含\(b\)类似。

第\(2\)种情况,设\(lft_i\)表示满足\(a_{j\sim j+s-1}\)的长度为\(i\)的后缀匹配\(b\)的长度为\(i\)的前缀的最小的\(j\),\(rit_i\)表示满足\(a_{j\sim j+s-1}\)的长度为\(i\)的前缀匹配\(b\)的长度为\(i\)的后缀的最大的\(j\),若没有满足条件的\(j\)则分别为\(+\infty,-\infty\)。“最小”和“最大”是基于贪心的思想,与第\(1\)种情况类似,为的是尽可能给另一个子串留位置。这样最后我们可以枚举\(i\in[0,s]\),若\(m-i\in[0,s]\)且\(lft_i+s-1<rit_{m-i}\),则存在答案\((lft_i,rit_{m-i})\)。

下面考虑\(lft\)和\(rit\)数组怎么求。以\(lft\)为栗例,我们令\(c=b+\texttt{!}+a\),对\(c\)跑一遍Z算法。\(\forall i\in[1,n]\),考虑若\(a1\)的后缀从第\(i\)位开始,能影响到哪些\(lft_j\)。显然\(j_{\max}=z_{c,m+1+j}\),因为最多能往后拓展\(z_{c,m+1+j}\)个字符,满足这个后缀与\(b\)的前缀匹配。\(j_{\min}\)呢?\(j\)越小,即\(a1\)在第\(i\)位后面的字符越少,那么\(a1\)在第\(i\)位前面的字符就越多,多到一定程度就会抵到位置\(1\),所以\(j_{\min}\)是刚好抵到的情况,如果不会抵到就是\(1\)。于是\(j_{\min}=\max(s-(i-1),1)\)。算出影响范围后,我们要去“影响”啊,即令\(\require{cancel}\forall j\in[j_{\min},j_{\max}],lft_j=\min(lft_j,i+j\cancel{-1}-s\cancel{+1})\)。这个可以用线段树维护,差分也可以,虽然都是\(\mathrm O(n\log n)\),但差分好写一点。

下面讲具体怎么差分:\(\forall k\in[0,m]\),维护一个添加序列\(add_k\)和删除序列\(del_k\)。对于每次影响,在\(add_{j_{\min}}\)和\(del_{j_{\max}+1}\)里插入\(i-s\)。最后维护一个multiset\(st\)(初始为\(\{+\infty\}\)),从\(i=1\)到\(i=m\)递推,每次将\(add_i\)里的元素insert进去,将\(del_i\)里的元素erase掉(注意如果写st.erase(x)会把所有的\(x\)都删掉,应该写st.erase(st.find(x))),*st.begin()+i就是\(lft_i\)。

\(rit\)数组的求法类似,不同在于\(c=b^\mathrm r+\texttt!+a^\mathrm r\),访问\(z\)数组时要访问在倒串中的位置,\(j_{\min}=\max(s-(n-i),1),j_{\max}=z_{c,m+1+(n+1-i)}\),影响为\(\forall j\in[j_{\min},j_{\max}],rit_j=\min(rit_j,i-j+1)\),\(st\)初始为\(\{-\infty\}\),每次插入\(i+1\),\(rit_i\)为*--st.end()-i

下面贴代码吧:(写不动了)

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int inf=0x3f3f3f3f;
const int N=500000,M=500000;
int n/*|a|*/,m/*|b|*/,s/*要选的字串的长度*/,t/*|c|*/;
int rev_pos(int pos){return n+1-pos;}//在倒串中的位置
char a[N+5],b[M+5],ra[N+5]/*rev(a)*/,rb[M+5]/*rev(b)*/,c[N+1+M+5]/*b+'!'+a或rb+'!'+ra*/;
void con(char str1[],char str2[]){//令c=str1+'!'+str2
t=0;
for(int i=1;i<=m;i++)c[++t]=str1[i];
c[++t]='!';
for(int i=1;i<=n;i++)c[++t]=str2[i];
}
int z1[N+1+M+1]/*a,b正着的z数组*/,z2[N+1+M+1]/*a,b倒着的z数组*/;
void z_init(int z[]){//Z算法
int zl=0,zr=0;
for(int i=2;i<=t;i++)
if(zr<i){
while(i+z[i]<=t&&c[i+z[i]]==c[1+z[i]])z[i]++;
if(z[i])zl=i,zr=i+z[i]-1;
}
else if(i+z[i-zl+1]<=zr)z[i]=z[i-zl+1];
else{
z[i]=zr-i+1;
while(i+z[i]<=t&&c[i+z[i]]==c[1+z[i]])z[i]++;
zl=i;zr=i+z[i]-1;
}
}
int lft[M+1],rit[M+1];
vector<int> dadd[M+1],ddel[N+1];//差分
multiset<int> st;
int main(){
cin>>n>>m>>s>>a+1>>b+1;
memcpy(ra+1,a+1,n+1);reverse(ra+1,ra+n+1);
memcpy(rb+1,b+1,m+1);reverse(rb+1,rb+m+1);
con(b,a);z_init(z1);
con(rb,ra);z_init(z2);
if(s>=m)//第1种情况
for(int i=1;i<=n;i++)
if(z1[m+1+i]==m){
int l=max(1,i-(s-m)),r=l+s;
if(r+s-1<=n)return cout<<"Yes\n"<<l<<" "<<r,0;
r=min(n,i+s-1)-s+1;l=r-s;
if(l>=1)return cout<<"Yes\n"<<l<<" "<<r,0;
}
//第2种情况
for(int i=1;i<=n;i++){//对lft影响
int l=max(s-(i-1),1),r=z1[m+1+i];
if(l>r)continue;
dadd[l].pb(i-s);if(r<m)ddel[r+1].pb(i-s);
}
st.insert(inf);//初始化
for(int i=1;i<=m;i++){//递推差分求lft
for(int j=0;j<dadd[i].size();j++)st.insert(dadd[i][j]);
for(int j=0;j<ddel[i].size();j++)st.erase(st.find(ddel[i][j]));
lft[i]=*st.begin()+i;
}
for(int i=1;i<=m;i++)dadd[i].clear(),ddel[i].clear();//数据不清空,爆零两行泪
for(int i=1;i<=n;i++){//对rit影响
int l=max(s-(n-i),1),r=z2[m+1+rev_pos(i)];
if(l>r)continue;
dadd[l].pb(i+1);if(r<m)ddel[r+1].pb(i+1);
}
st.clear();st.insert(-inf);//初始化
for(int i=1;i<=m;i++){//递推差分求rit
for(int j=0;j<dadd[i].size();j++)st.insert(dadd[i][j]);
for(int j=0;j<ddel[i].size();j++)st.erase(st.find(ddel[i][j]));
rit[i]=*--st.end()-i;
}
// for(int i=1;i<=m;i++)printf("lft[%d]=%d rit[%d]=%d\n",i,lft[i],i,rit[i]);
for(int i=0;i<=s;i++)if(0<=m-i&&m-i<=s)
if(lft[i]+s-1<rit[m-i])//不相交
return cout<<"Yes\n"<<lft[i]<<" "<<rit[m-i],0;
puts("No");
return 0;
}

CodeForces 955D Scissors的更多相关文章

  1. Z算法

    Z算法 Z算法是一种用于字符串匹配的算法.此算法的核心在于\(z\)数组以及它的求法. (以下约定字符串下标从\(1\)开始) \(\bm z\)数组和Z-box 定义\(z\)数组:\(z_{a,i ...

  2. CodeForces 219B Special Offer! Super Price 999 Bourles!

    Special Offer! Super Price 999 Bourles! Time Limit:1000MS     Memory Limit:262144KB     64bit IO For ...

  3. CodeForces 173A Rock-Paper-Scissors 数学

    Rock-Paper-Scissors 题目连接: http://codeforces.com/problemset/problem/173/A Description Nikephoros and ...

  4. Codeforces Gym 100015A Another Rock-Paper-Scissors Problem 找规律

    Another Rock-Paper-Scissors Problem 题目连接: http://codeforces.com/gym/100015/attachments Description S ...

  5. Codeforces Round #338 (Div. 2) C. Running Track dp

    C. Running Track 题目连接: http://www.codeforces.com/contest/615/problem/C Description A boy named Ayrat ...

  6. 2018 ACM-ICPC 中国大学生程序设计竞赛线上赛 H题 Rock Paper Scissors Lizard Spock.(FFT字符串匹配)

    2018 ACM-ICPC 中国大学生程序设计竞赛线上赛:https://www.jisuanke.com/contest/1227 题目链接:https://nanti.jisuanke.com/t ...

  7. Codeforces Round #301 (Div. 2) D. Bad Luck Island 概率DP

    D. Bad Luck Island Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/540/pr ...

  8. Codeforces Round #597 (Div. 2) B. Restricted RPS

    链接: https://codeforces.com/contest/1245/problem/B 题意: Let n be a positive integer. Let a,b,c be nonn ...

  9. CodeForces - 1245 B - Restricted RPS(贪心)

    Codeforces Round #597 (Div. 2) Let nn be a positive integer. Let a,b,ca,b,c be nonnegative integers ...

随机推荐

  1. 201871010110 - 李华 《面向对象程序设计(java)》第二周学习总结

    第一部分:理论知识学习部分 一.简单的Java程序应运程序 1.标识符0标识符由字母.下划线.美元符号和数字组成,且第一个符号不能为数字.   标识符可用作:类名.对象名.变量名.方法名.数组名.文件 ...

  2. windows 上robot framework 读取sqlite3提示:OperationalError: unable to open database file错误

    原因:路径写的不正确. 正确的写法:'D:/Python27/163/demo.db' 或者 r 'E:\\rf-demos-master\\DatabaseDemo\\demo.db' Connec ...

  3. 第三章 linux常用的命令

    安装笔记: 1 安装linux操作系统时,会默认创建一个超级管理员帐号:root 2 安装时,当进行到选择哪种类型的安装时,我们选择"使用所有空间"的类型 Linux概念性的东西 ...

  4. css字体名称中英文对照表

    华文细黑:STHeiti Light [STXihei] 华文黑体:STHeiti 华文楷体:STKaiti 华文宋体:STSong 华文仿宋:STFangsong 俪黑 Pro:LiHei Pro ...

  5. offsetWidth的bug

    #div1{width:200px;border:1px solid red;} 这个时候如果用 offsetWidth 提取 #div1 的宽  得到的值是 202: 也就是说 offsetWidt ...

  6. 【oracle】ORA-00257 archiver error. Connect internal only, until freed

    [原因]归档日志太多导致磁盘空间过小. [解决办法]删除日志或加大空间

  7. 图的遍历 | 1076 bfs

    bfs踩了很多坑才写完.注意:出队时不做是否vis判断,但是要加上vis[出队顶点]=1 .入队时进行判断,并且也要 vis[入队顶点]=1 #include <stdio.h> #inc ...

  8. IIS启动后不在桌面显示

    1.问题 周末一过,准备投入到紧张激烈的工作之中.不曾想IIS打开后不在桌面显示了,任务栏有打开的图标,配置的网站可以正常打开.尝试重装无果. 2.解决 Win+R,在运行中输入inetmgr.exe ...

  9. 关于组件--React

    组件按照页面结构可以分成,头部.底部.内容部分.这样就可以写三个组件. 组件内部还可以包含下一级组件, 比如头部,可以包含登录,注册等组件. 底部 可以 包含一些链接等. 内容部分可以包含表单组件.按 ...

  10. Spring Boot 知识笔记(热部署)

    热部署原理: 使用了两个ClassLoader,一个Classloader加载那些不会改变的类(第三方Jar包),另一个ClassLoader加载会更改的类,称为restart ClassLoader ...