刷題總結——字符串(ssoj)
阿新 • • 發佈:2017-10-16
sso cnblogs 其中 ctime 題解 += 不用 const void
題目:
給定n個小的字符串T和一個大的字符串S,先輸出T總共再S中出現了多少次
然後q個詢問···每次修改S上的一個字母,然後再次輸出上述答案···
n小於1000,q<200000,T的總長度和S的長度都小於100000;
題解:
我們可以發現,每次修改位置P,那麽S影響的範圍只有在P-MAX到P+MAX的範圍,其中MAX為T的最長長度····所以將這一範圍的S跑一邊AC自動機··然後更新答案即可··
這道題也讓我發現我做AC自動機以來一直有的一個不好的習慣··每次求出現次數都是暴力跳fail指針,這樣再這道題裏直接T····
其實再我們bfs構建fail指針時,設u的指針為v,我們可以直接tree[u].cnt+=tree[v].cnt,這樣每次加的時候直接加上一個節點cnt就可以了··不用暴力跳fail···代碼:
代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; queue<int>que; const int N=100005; structnode { int son[26],cnt,fail; void clear() { memset(son,0,sizeof(son)); cnt=fail=0; } }tree[N]; int n,m,T,tot,maxx=0; char s[N],t[5]; inline int R() { char c;int f=0; for(c=getchar();c<‘0‘||c>‘9‘;c=getchar()); for(;c<=‘9‘&&c>=‘0‘;c=getchar()) f=(f<<3)+(f<<1)+c-‘0‘; return f; } int buf[1024]; inline void W(int x){ if(!x){putchar(‘0‘);return ;} if(x<0){putchar(‘-‘);x=-x;} while(x) buf[++buf[0]]=x%10,x/=10; while(buf[0]) putchar(buf[buf[0]--]+48); return ; } inline void build() { int po=1; int len=strlen(s);maxx=max(maxx,len); for(int i=0;i<len;i++) { if(!tree[po].son[s[i]-‘a‘]) tree[tree[po].son[s[i]-‘a‘]=++tot].clear(); po=tree[po].son[s[i]-‘a‘]; } tree[po].cnt++; } inline void buildfail() { que.push(1); while(!que.empty()) { int u=que.front();que.pop(); for(int i=0;i<26;i++) { int v=tree[u].fail; while(!tree[v].son[i]) v=tree[v].fail; v=tree[v].son[i];int w=tree[u].son[i]; if(w) tree[w].fail=v,que.push(w),tree[w].cnt+=tree[v].cnt; else tree[u].son[i]=v; } } } int main() { //freopen("string.in","r",stdin); //freopen("string.out","w",stdout); n=R(),m=R(); for(int i=0;i<26;i++) tree[0].son[i]=1; tree[tot=1].clear(); for(int i=1;i<=n;i++) { scanf("%s",s); build(); } buildfail(); scanf("%s",s); int len=strlen(s),a; int now=1,ans=0; for(int i=0;i<len;i++) { now=tree[now].son[s[i]-‘a‘]; ans+=tree[now].cnt; } W(ans),putchar(‘\n‘); while(m--) { a=R();scanf("%s",t); int now=1,ans1=0,ans2=0; for(int i=max(0,a-maxx);i<=min(a+maxx-1,len-1);i++) { now=tree[now].son[s[i]-‘a‘]; ans1+=tree[now].cnt; } ans-=ans1; s[a-1]=t[0];now=1; for(int i=max(0,a-maxx);i<=min(a+maxx-1,len-1);i++) { now=tree[now].son[s[i]-‘a‘]; ans2+=tree[now].cnt; } ans+=ans2; W(ans),putchar(‘\n‘); } return 0; }
刷題總結——字符串(ssoj)