【题解】P4696 [CEOI2011] Matching
题目描述
对于整数序列 和 的排列 ,称 符合 ,当且仅当:
-
中任意两个数字互不相同;
-
将 从小到大排序后,将会得到 。
现在给出 的排列 和序列 ,请你求出哪些 的子串符合排列 。
题解
人类智慧题,解法是不容易想到的。
有 的线段树hash,然而有更优秀的 kmp。
考虑重新定义kmp的相等,我们记录比当前数小的最大的数(前驱)和大的最小的数(后继),如果所有的数都满足相对位置前驱处的数比它小且后继处的数比它大那么当前序列是满足的。
重写下比较函数就行。
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=1000010;
int n,m;
int p[N],h[N];
int pos[N],val[N];
int les[N],mor[N];
int nex[N];
int ans,ge[N];
struct Node
{
int next,prev;
}node[N];
bool check1(int n1,int n2)
{
bool flag=true;
if(les[n1]&&val[n2-(n1-les[n1])]>=val[n2])flag=false;
if(mor[n1]&&val[n2-(n1-mor[n1])]<=val[n2])flag=false;
return flag;
}
bool check2(int n1,int n2)
{
bool flag=true;
if(les[n1]&&h[n2-(n1-les[n1])]>=h[n2])flag=false;
if(mor[n1]&&h[n2-(n1-mor[n1])]<=h[n2])flag=false;
return flag;
}
int main()
{
n=rd(),m=rd();
for(int i=1;i<=n;i++)
{
p[i]=rd();
val[p[i]]=i;
}
for(int i=1;i<=m;i++)h[i]=rd();
for(int i=1;i<=n;i++)pos[i]=p[i];
for(int i=1;i<=n;i++)node[i].next=i+1,node[i].prev=i-1;
for(int i=n;i>=1;i--)
{
les[i]=pos[node[val[i]].prev];
mor[i]=pos[node[val[i]].next];
node[node[val[i]].next].prev=node[val[i]].prev;
node[node[val[i]].prev].next=node[val[i]].next;
}
for(int i=1;i<=n;i++)
{
int j=nex[i-1];
while(j>0&&check1(j+1,i)==false)j=nex[j];
if(check1(j+1,i)==true&&j+1<i)j++;
nex[i]=j;
}
int j=0;
for(int i=1;i<=m;i++)
{
while(j>0&&check2(j+1,i)==false)j=nex[j];
if(check2(j+1,i)==true)j++;
if(j==n)
{
j=nex[j];
ge[++ans]=i-n+1;
}
}
cout<<ans<<endl;
for(int i=1;i<=ans;i++)printf("%d ",ge[i]);
return 0;
}
代码不想写了喵
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】