【題目描述】數組
對於一個字符集大小爲C的字符串pp,能夠將任意兩個字符在p中的位置進行互換,例如p=12321,交換1、21、2獲得21312,交換1、4獲得42324,交換能夠進行任意次。若交換後p變成了字符串q,則成q與p是匹配的。函數
給定兩個字符集大小爲C的字符串s、t,求出s中有多少個連續子串與t匹配。spa
【輸入】code
第一行兩個整數T、C,分別表示數據組數和字符集大小,字符用1∼C的整數來表示。blog
對於每組數據:第一行兩個整數n、m,分別表示s、t的長度。字符串
第二行n個正整數表示s。get
第三行m個正整數表示t。string
【輸出】it
對於每組數據,輸出包括兩行:io
第一行一個正整數k,表示s中有k個連續子串與t匹配。
第二行從小到大輸出k個數,表示s中與t匹配的連續子串的首位下標(下標從1開始)。
【輸入樣例】
3 3
6 3
1 2 1 2 3 2
3 1 3
6 3
1 2 1 2 1 2
3 1 3
6 3
1 1 2 1 2 1
3 1 3
【輸出樣例】
3
1 2 4
4
1 2 3 4
3
2 3 4
【數據規模及約定】
對於10%的數據,知足n,m,C≤1000n,m,C≤1000;
對於另外20%的數據,知足n,m≤105,C≤40n,m≤105,C≤40;
對於另外30%的數據,知足n,m,C≤105n,m,C≤105;
對於100%的數據,知足1≤n,m,C≤106,T=31≤n,m,C≤106,T=3。
【分析】
這其實就是一道KMP的題
題目的難點在於如何交換字符
咱們能夠開一個數組l[1~c]
l[x]表示上一個x出現的位置
a[i]表示字符s[i]離上一個相同字符出現的距離
b[i]表示字符t[i]離上一個相同字符出現的距離
而後就是KMP
難點是如何判斷s[i](t[i])的上一個相同字符是否在模式串以外
這其實很簡單
直接判斷上一個x出現的距離是否大於j不就好了
因而開兩個函數
inline int jdg(int x,int l){return x<l?x:0;}//判斷s[i](t[i])的上一個相同字符是否在匹配範圍內 //是就返回a[i](b[i]),否就返回0 inline bool eq(int x,int y,int l){return jdg(x,l)==jdg(y,l);}//判斷是否匹配
經歷千辛萬苦
【AC代碼】
#include<cstdio> #include<cstring> #include<algorithm> #define N (1000000+2) #define C (1000000+2) using namespace std; int p[N]; int a[N],b[N]; int l[C];//這裏很重要,我把C開小了交了不知多少次都沒有過 int ans[N]; template<typename T>inline void read(T& x){ char temp=getchar();bool u=0; for(x=0;temp<'0'||temp>'9';u=temp=='-',temp=getchar()); for(;temp>='0'&&temp<='9';x=x*10+temp-'0',temp=getchar()); if(u)x=-x; return ; }//快讀 inline int jdg(int x,int l){return x<l?x:0;}//判斷s[i](t[i])是否在匹配範圍內 //是就返回a[i](b[i]),否就返回0 inline bool eq(int x,int y,int l){return jdg(x,l)==jdg(y,l);}//判斷是否匹配 void work(){ register int i,j,x; register int n,m; read(n); read(m); memset(a,0,sizeof a); memset(b,0,sizeof b);//有多組數據,必定要初始化 memset(p,0,sizeof p);//不然就會成爲某dengzhaoxing之二 memset(l,0,sizeof l); for(i=1;i<=n;i++){ read(x); a[i]=i-l[x];//將a[i]賦值爲字符x與上一x之間的距離 l[x]=i; } memset(l,0,sizeof l);//輸入s和t以前都要初始化l for(i=1;i<=m;i++){ read(x); b[i]=i-l[x];//將b[i]賦值爲字符x與上一x之間的距離 l[x]=i; } for(i=1,j=0;i<m;i++){ while(j&&!eq(b[i+1],b[j+1],j+1)) j=p[j]; if(eq(b[i+1],b[j+1],j+1)) j++; p[i+1]=j; }//KMP初始化p數組 for(x=i=j=0;i<n;i++){ while(j&&!eq(a[i+1],b[j+1],j+1)) j=p[j]; if(eq(a[i+1],b[j+1],j+1)) j++; if(j==m){ ans[++x]=i+2-m; j=p[j]; } }//KMP匹配 printf("%d\n",x); for(i=1;i<=x;i++) printf("%d ",ans[i]);//輸出答案 putchar('\n'); return ; } int main(){ register int t,c,i; read(t); read(c); for(i=1;i<=t;i++) work(); return 0; }