聯考20200721 T2 s2mple
阿新 • • 發佈:2020-07-22
分析:
什麼神仙題,考場上暴力都不會寫
(深深地明白了自己是個廢物的事實)
我們轉換一下統計方式,假設要查詢的串為\(P\),在前面加上一個串\(Q\),在後面加上一個串\(R\),得到的新串為\(T\),與前面的串Q形成一個二元組\((T,Q)\)
答案即為本質不同的二元組\((T,Q)\)個數,其中\(T\)為\(S\)的子串
(感性理解一下發現很對(捂臉)
先統計\(Q+P\)的個數
構建一個SAM,答案即為fail樹上\(P\)所在節點的後代的所有子串加上\(P\)所在節點集合長度不小於\(|P|\)的子串
所以該節點對權值的貢獻可以表示為\(−|P|+b\),其中\(b\)是一個常數,我們可以事先處理出來。
在\(P\)
那麼某一個點的值會被寫成\(k|P|+b\)的形式,我們沿著邊維護每個點的\(k,b\)即可
轉移時注意\(k|P|+b\)會變成\(k(|P|+1)+b=k|P|+(k+b)\)。
每次詢問找到|P|對應的節點,把|P|代進去算即可,這個可以在fail樹上倍增找
#include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #include<string> #define maxn 1000005 #define INF 0x3f3f3f3f #define MOD 998244353 using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,Q; char s[maxn]; struct node{ int len,nxt[26],fa; }t[maxn]; int lst=1,tot=1; struct cp{ long long b,k; cp(){} cp(long long x,long long y){b=x,k=y;} friend cp operator +(cp x,cp y){return cp(x.b+y.b,x.k+y.k);} }f[maxn]; int d[maxn]; long long sz[maxn]; int F[maxn][20],pos[maxn]; inline bool cmp(int x,int y) {return t[x].len<t[y].len;} inline void ins(int c) { int p=lst,np=lst=++tot; t[np].len=t[p].len+1; while(p&&!t[p].nxt[c])t[p].nxt[c]=np,p=t[p].fa; if(!p)t[np].fa=1; else { int q=t[p].nxt[c]; if(t[q].len==t[p].len+1)t[np].fa=q; else { int nq=++tot; memcpy(t[nq].nxt,t[q].nxt,sizeof t[q].nxt); t[nq].fa=t[q].fa,t[nq].len=t[p].len+1; t[q].fa=t[np].fa=nq; while(p&&t[p].nxt[c]==q)t[p].nxt[c]=nq,p=t[p].fa; } } } inline int find(int x,int l) { for(int i=19;~i;i--)if(F[x][i]&&t[F[x][i]].len>=l)x=F[x][i]; return x; } int main() { n=getint(),Q=getint(); scanf("%s",s+1); for(int i=1;i<=n;i++)ins(s[i]-97),pos[i]=lst; for(int i=1;i<=tot;i++) { d[i]=i; sz[i]=t[i].len-t[t[i].fa].len; if(t[i].fa)F[i][0]=t[i].fa; } for(int j=1;j<20;j++)for(int i=1;i<=tot;i++) F[i][j]=F[F[i][j-1]][j-1]; sort(d+1,d+tot+1,cmp); for(int i=tot;i;i--) { int x=d[i];sz[t[x].fa]+=sz[x]; f[x]=cp(sz[x]+t[t[x].fa].len+1,-1); } for(int i=tot;i;i--) { int x=d[i]; for(int j=0;j<26;j++)if(t[x].nxt[j]) { int v=t[x].nxt[j]; f[x]=f[x]+cp(f[v].b+f[v].k,f[v].k); } } while(Q--) { int l=getint(),r=getint(); int tmp=find(pos[r],r-l+1); printf("%lld\n",f[tmp].b+f[tmp].k*(r-l+1)); } }