Censor SCU - 4438
题意:给你两串字符串w和p。在p中不停删除w,直到p中没有w。输出此时剩余的字符串。
解题思路:
字符串问题考虑hash做法。先求出字符串w的哈希值。然后遍历字符串p,设pos是answer数组中的下标。check 以现在找到的这个点为终点是否可以构成字符串 w。如果可以,pos点向前移动len_w个单位。
难点:
如何以常数级复杂度去check以现在找到的这个点为终点是否可以构成字符串w?
比如我们在123这个数字中找是否存在23。
- pos=1 1显然不行,因为pos小于len(23)=2
- pos=2 12-0≠23 所以不行
- pos=3 123-100=23所以可行
bool check(int pos){
if (pos<len_w-1) return false;
if (hash_p[pos]-hash_p[pos-len_w]*Hash[len_w]==hash_w[len_w-1]) return true;
else return false;
}
AC代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
//#pragma GCC optimize(3,"Ofast","inline")
#define LL long long
#define MT(a,b) memset(a,b,sizeof(a))
const int mod=1000007;
const int maxn=5e6+5;
const int ONF=-0x3f3f3f3f;
const int INF=0x3f3f3f3f;
char w[maxn],p[maxn],ans[maxn];
unsigned LL k=233,Hash[maxn],hash_w[maxn],hash_p[maxn];
int len_w,len_p;
void get(){
len_w=strlen(w),len_p=strlen(p);
hash_w[0]=(unsigned LL) w[0];
Hash[0]=1;
for (int i=1;i<=len_w;i++){
hash_w[i]=hash_w[i-1]*k+(unsigned LL) w[i];
Hash[i]=Hash[i-1]*k;
}
}
bool check(int pos){
if (pos<len_w-1) return false;
if (hash_p[pos]-hash_p[pos-len_w]*Hash[len_w]==hash_w[len_w-1]) return true;
else return false;
}
void solve(){
get();
int pos=0;
for (int i=0;i<len_p;i++){
ans[pos++]=p[i];
hash_p[pos]=hash_p[pos-1]*k+(unsigned LL)p[i];
if (check(pos)) pos-=len_w;
}
for (int i=0;i<pos;i++) printf("%c",ans[i]);
printf("\n");
}
int main (){
while (~scanf("%s%s",w,p)){
solve();
}
return 0;
}