题面(简化)
给定一个长度为
在长度最短的前提下使得
字符串
简化后的题面可能难以理解,防一组样例来进一步说明:
s : 5 3 5 3 6 6
t : 3 5 6
符合题目要求的子串为 3 5 3 6,输出为:2 4
题目有多组测试,数据范围:
题解
1.从暴力出发
这题的暴力非常简单,直接枚举左端点
这样的复杂度很显然是
如果你已经打完了这个暴力,那么恭喜你,其实你已经接近
让我们重走一遍我考试时的心路历程。
2.优化
一个很简单的优化:匹配之前预处理出
这个优化看似没什么用,但是它会把时间复杂度从
可以发现
3.进一步优化
在刚才的优化基础上,我们再进一步优化。
考虑一个问题:为什么一定要预处理出
实际上,任何一个
若预处理出
考虑怎样选择
为方便讲述,我们下面把在
显然的,
是不是感觉有点奇怪?
也就是说,
那么来吧,放手一搏!我们就赌这道题目没有
显然,至少在这题,我们赢下了这场豪赌。
4.反思
虽然这道题确实是过了,但是我们还是得居安思危。这题不卡并不是所有题目都不会卡,在考后还是要多看正解。
这里有 @ShwStone 的 dp 做法,应该是正解:Link
下面有完整代码与自己干出来的一组
完整代码
代码中用桶进行了预处理,最后在 33~34 行得到了基准值
36~62 行是匹配,还是有一点细节的,但是不难写。
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
return s*w;
}
const int N=1e6+5;
vector<int> st;
int T,s[N],t[N],bkt[N],bks[N];
int main()
{
//freopen("qlx.in","r",stdin);
//freopen("qlx.out","w",stdout);
T=read();
for(int ccc=1,n,m;ccc<=T;ccc++)
{
int mins=INT_MAX,c=0,sv=0,flag=0,minl=INT_MAX,ans1=0,ans2=0;
memset(bkt,0,sizeof(bkt));
memset(bks,0,sizeof(bks));
st.clear();
n=read(),m=read();
for(int i=1;i<=n;i++) s[i]=read();
for(int i=1;i<=m;i++) t[i]=read(),bkt[t[i]]++;
for(int i=1;i<=n;i++) if(s[i]<N) if(bkt[s[i]]) bks[s[i]]++;
for(int i=1;i<=m;i++) if(bks[t[i]]&&bks[t[i]]<mins) mins=bks[t[i]],c=t[i];
for(int i=1;i<=m;i++) if(t[i]==c){sv=i;break;}
for(int i=1;i<=n;i++) if(s[i]==c) st.emplace_back(i);
for(int i=0;i<st.size();i++)
{
int v=st[i],q=sv+1,resr=n,flag1=0,flag2=0;
for(;v<=n;v++)
{
if(q>m) break;
if(s[v]==t[q]) q++;
flag1=1;
}
if(q<=m) continue;
resr=v-flag1,v=st[i],q=sv-1;
for(;v>=1;v--)
{
if(q<1) break;
if(s[v]==t[q]) q--;
flag2=1;
}
if(q<1)
{
if(resr-(v+flag2)+1<minl)
{
ans1=v+flag2,ans2=resr;
minl=resr-(v+flag2)+1;
}
flag=1;
}
}
if(flag) printf("%d %d\n",ans1,ans2);
else printf("-1\n");
}
}
hack数据
hack 数据生成代码:
#include<bits/stdc++.h>
using namespace std;
int n,len,m;
int main()
{
freopen("qlx.in","w",stdout);
cout<<1<<"\n";cout<<"1000000 2"<<endl;
for(int i=1;i<=1000000/2;i++) cout<<"1 ";
for(int i=1;i<=1000000/2;i++) cout<<"2 ";
cout<<endl;
cout<<"1 2"<<endl;
}
多测组数为一组,
就这么个玩意儿程序跑了