bzoj1729:[Usaco2005 dec]Cow Patterns 牛的模式匹配(kmp+思維)
阿新 • • 發佈:2018-12-09
Problem
有一個 個數的數列 ,其數字範圍為 ~ 。 還有 個數 。 問從數列 數列取出連續 個數,排名與 中排名一致的情況有多少種
Solution
我們考慮這個 ,將其變成所以可能的序列,然後和原串進行 可能的序列可以用遞迴求解… 然而這樣肯定複雜度大啊!
所以我們改進…(改進完和原來就沒啥關係了…) 但本質還是改變模式串。 先來一波定義,定義 中有 個數
在求這個模式串的過程中,要是每位都去重新考慮就次數太多了…
我們將模式串進行一波離散化
那我們列舉模式串中的數字對應數列 中為幾,然後判斷從哪些位開始的在模式串這個數字中成立。結果就是所以模式串每一個數字都模擬出來,且都包含的結果
說不清..上程式碼吧…
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100010
#define inf 0x3f3f3f3f
int n,m,k,ans=0,nxt[N],f[N],s[N],t[N],a[N],b[N],c[N],maxx[N],maxy[N];
inline void KMP(int step,int x){
for(int i=1;i<=n;i++) if(a[i]==x) s[i]=x;else s[i]=0;
for(int i=1;i<=m;i++) if(b[i]==step) t[i]=x;else t[i]=0;
nxt[1]=0;
for(int i=2,j=0;i<=m;i++){
while(j && t[i]!=t[j+1]) j=nxt[j];
if(t[i]==t[j+1]) j++;
nxt[i]=j;
}
for(int i=1,j=0;i<=n;i++){
while(j && (j==m || s[i]!=t[j+1])) j=nxt[j];
if(s[i]==t[j+1]) j++;
if(j==m) maxy[i-m+1]=x;
}
}
int main(){
while(scanf("%d%d%d",&n,&m,&k)>0){
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(c,0,sizeof(c));
for(int i=1;i<=m;i++) scanf("%d",&b[i]),c[b[i]]=1;
memset(maxx,0,sizeof(maxx));
for(int i=1;i<=k;i++){
if(!c[i]) continue;
for(int j=1;j<=n;j++) maxy[j]=inf;
for(int j=1;j<=k;j++)
KMP(i,j); //第i小的數j,看每位是否能通過這個數得到
for(int j=1;j<=n;j++) if(maxx[j]>=maxy[j]) maxx[j]=inf;else maxx[j]=maxy[j];
}
for(int i=1;i<=n;i++) if(maxx[i]!=inf) ans++;
printf("%d\n",ans);
for(int i=1;i<=n;i++) if(maxx[i]!=inf) printf("%d\n",i);
}
return 0;
}