zoukankan      html  css  js  c++  java
  • 【ybtoj】【kmp】字符串匹配

    题意

    image
    image

    题解

    可以考虑转化到 KMP 相关问题。
    KMP 的常规匹配是看当前字符位是否相同,而本题可以改为当前字符和前一个相同字符的距离是否相同,因为这样的字符串经过反转之后一定能变成相同的。
    当前字符到前一个相同字符的距离 (pre_i) 数组可以预处理。
    注意:当与前一个相同字符的距离大于当前匹配到的位置时,是没有意义的,当作首次出现处理(赋值为 (0))。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const int INF = 0x3f3f3f3f,N = 1e6+10;
    inline ll read()
    {
    	ll ret=0;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    inline int ask(int l,int r){return l<r?l:0;}
    int T,c,n,m,s[N],t[N];
    int lst[N],preb[N],prea[N],pos[N],nxt[N],ans;
    inline void pretreat()
    {
    	int j=0;
    	for(int i=1;i<m;i++) 
    	{
    		while(j&&ask(preb[i+1],j+1)!=ask(preb[j+1],j+1)) j=nxt[j];
    		if(ask(preb[i+1],j+1)==ask(preb[j+1],j+1)) j++;
    		nxt[i+1]=j; 
    	}
    }
    inline void kmp()
    {
    	int j=0; ans=0;
    	for(int i=0;i<n;i++) 
    	{
    		while(j&&ask(prea[i+1],j+1)!=ask(preb[j+1],j+1)) j=nxt[j];
    		if(ask(prea[i+1],j+1)==ask(preb[j+1],j+1)) j++;
    		if(j==m) pos[++ans]=i+1-m+1,j=nxt[j];
    	}
    }
    int main()
    {
    	T=read(),c=read();
    	while(T--)
    	{
    		n=read(),m=read();
    		for(int i=1;i<=n;i++) s[i]=read();
    		for(int i=1;i<=m;i++) t[i]=read();
    		memset(lst,0,sizeof(lst));
    		for(int i=1;i<=n;i++) 
    		{
    			prea[i]=ask(i-lst[s[i]],m);
    			lst[s[i]]=i;
    		}
    		memset(lst,0,sizeof(lst));
    		for(int i=1;i<=m;i++) 
    		{
    			preb[i]=ask(i-lst[t[i]],m);
    			lst[t[i]]=i;
    		}
    		pretreat();
    		kmp();
    		printf("%d
    ",ans);
    		for(int i=1;i<=ans;i++) 
    			printf("%d ",pos[i]);
    		printf("
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    luogu P3657 (NOIP2017) 跳房子(二分+DP+单调队列)
    BZOJ 3331 (Tarjan缩点+树上差分)
    Libre OJ 2255 (线段树优化建图+Tarjan缩点+DP)
    LibreOJ 6177 题解(状压DP)
    BZOJ 1179 (Tarjan缩点+DP)
    BZOJ 4919 (树上LIS+启发式合并)
    BZOJ 1100 &&luogu 3454(计算几何+KMP)
    HDU 3228 题解(最小生成树)(Kruskal)(内有详细注释)
    Codeforces 1058C(思维+最大公因数)
    周记 2015.05.30
  • 原文地址:https://www.cnblogs.com/conprour/p/15305716.html
Copyright © 2011-2022 走看看