題解 SP7022 【CPATTERN - Cow Patterns】
阿新 • • 發佈:2020-07-14
本篇題解用於作者本人加深理解,也歡迎大家閱讀。
這道題的正解是$KMP$加上樹狀陣列,記錄每一個位置前幾個位置比其小的、相等的、大的數的數量,比較方式便是比較相應的數量,若相等,則匹配成功。
但是本篇題解使用了$Hash$的做法,因為$1<=s<=25$,所以我們可以利用一個數組,並利用二進位制的壓縮方式,記錄每一個數存在的位置。即:
$hash[i]$表示數字$i$在$k$的長度中出現的位置的二進位制壓縮。
如$hash[i]=1000101_2$就表示$i$在長度為$k=7$的序列內出現在了$1,5,7$的位置($or$出現在了$1 ,3,7$的位置(看個人理解)),接著再按照$s$從小到大比較二進位制壓縮,即可判斷是否一致。
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=100005,M=25005,S=30,MOD=7710343; int n,m,s,len; int a[N],b[M]; ll ksm[M],hsa[S],hsb[S]; int ans[N],lans=0; inline int read() { char c=getchar(); while(c<'0'||'9'<c) c=getchar(); int x=0; while('0'<=c&&c<='9') { x*=10; x+=c-'0'; c=getchar(); } return x; } int main() { cin>>n>>m>>s; for(int i=1;i<=n;++i) a[i]=read(); for(int i=1;i<=m;++i) b[i]=read(); ksm[0]=1; for(int i=1;i<=m;++i) ksm[i]=ksm[i-1]*2%MOD; for(int i=1;i<=m;++i) { len=max(len,b[i]); for(int j=1;j<=s;++j) { hsb[j]=(hsb[j]*2+(b[i]==j))%MOD; } } for(int i=1;i<=n;++i) { for(int j=1;j<=s;++j) { hsa[j]=(hsa[j]*2+(a[i]==j))%MOD; } if(i>=m) { // printf("%d\n",i-m+1); bool ok=true; int aa=1,bb=1,cnt=0; while(aa<=s&&bb<=s) { while(aa<=s&&!hsa[aa]) ++aa; while(bb<=s&&!hsb[bb]) ++bb; if(aa>s||bb>s) break; if(hsa[aa]==hsb[bb]) { ++cnt; // printf("%d %d\n",aa,bb); } else { ok=false; break; } ++aa; ++bb; } // printf("%d %d %d\n",cnt,len,ok); if(cnt==len&&ok) ans[++lans]=i-m+1; for(int j=1;j<=s;++j) { hsa[j]=((hsa[j]-ksm[m-1]*(a[i-m+1]==j))%MOD+MOD)%MOD; } } } printf("%d\n",lans); for(int i=1;i<=lans;++i) printf("%d\n",ans[i]); return 0; }