题解:P12490 [集训队互测 2024] 字符串
典题,从 Runs 模板拷过来的代码上加点东西就行了。
设
一个
考虑求出满足
如果再求出满足
那么最终答案就是
按照字典序从大到小加入后缀可以简单地求出
思考
设
如果没有
思考
时间复杂度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace Fread {
const int SIZE=1<<21;char buf[SIZE],*S,*T;
inline char getchar() {if(S==T){T=(S=buf)+fread(buf,1,SIZE,stdin);if(S==T)return '\n';}return *S++;}
}
namespace Fwrite {
const int SIZE=1<<21;
char buf[SIZE],*S=buf,*T=buf+SIZE;
inline void flush(){fwrite(buf,1,S-buf,stdout);S=buf;}
inline void putchar(char c){*S++=c;if(S==T)flush();}
struct POPOSSIBLE{~POPOSSIBLE(){flush();}}ztr;
}
#define getchar Fread :: getchar
#define putchar Fwrite :: putchar
namespace Fastio{
struct Reader{
template<typename T>
Reader& operator >> (T& x) {
char c=getchar();T f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}x=0;
while(c>='0'&&c<='9'){x=x*10+(c-'0');c=getchar();}x*=f;
return *this;
}
Reader& operator >>(string &s){
char c=getchar();s.clear();
while(c==' '||c=='\n')c=getchar();
while(c!=' '&&c!='\n'&&c!='\r'){s+=c;c=getchar();}
return *this;
}
Reader(){}
}cin;
struct Writer{
template<typename T>
Writer& operator << (T x) {
if(x==0){putchar('0');return *this;}
if(x<0){putchar('-');x=-x;}
static int sta[45];int top=0;
while(x){sta[++top]=x%10;x/=10;}
while(top){putchar(sta[top]+'0');--top;}
return *this;
}
Writer& operator << (char c) {putchar(c);return *this;}
Writer(){}
}cout;
}
#define fi first
#define sec second
typedef pair<int,int> pii;
#define cin Fastio :: cin
#define cout Fastio :: cout
bool st;
const int N=1e6+10;
string s;int n,m,tot,flag[N];
int x[N],y[N],c[N],cas,ans[N];
struct SA{
int sa[N],rk[N],h[N],f[20][N];
inline void Suffix_Sort(){
int m=130;
for(int i=1;i<=n;++i) ++c[x[i]=s[i]];
for(int i=1;i<=m;++i) c[i]+=c[i-1];
for(int i=n;i;--i) sa[c[x[i]]--]=i;
for(int i=0;i<=m;++i) c[i]=0;
for(int k=1;k<=n;k<<=1){
int ct=0;
for(int i=n-k+1;i<=n;++i) y[++ct]=i;
for(int i=1;i<=n;++i) if(sa[i]>k) y[++ct]=sa[i]-k;
for(int i=1;i<=n;++i) ++c[x[i]];
for(int i=1;i<=m;++i) c[i]+=c[i-1];
for(int i=n;i;--i) sa[c[x[y[i]]]--]=y[i],y[i]=0;
for(int i=0;i<=m;++i) c[i]=0;
swap(x,y);x[sa[1]]=ct=1;
for(int i=2;i<=n;++i) x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?ct:++ct;
if(ct==n) break;
m=ct;
}
for(int i=1;i<=n;++i) rk[sa[i]]=i;
}
inline void getheight(){
int k=0;
for(int i=1;i<=n;++i){
if(k) --k;
if(rk[i]==1) continue;
int j=sa[rk[i]-1];
while(j+k<=n&&s[i+k]==s[j+k]) ++k;
h[rk[i]]=k;
}
}
inline void init(){
for(int i=1;i<=n;++i) f[0][i]=h[i];
for(int i=1;i<=__lg(n);++i) for(int j=1;j+(1<<i)-1<=n;++j) f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]);
}
inline int ask(int i,int j){
i=rk[i];j=rk[j];if(i>j) swap(i,j);
++i;int g=__lg(j-i+1);
return min(f[g][i],f[g][j-(1<<g)+1]);
}
}lcp,lcs;
bool ed;
struct TreeArray{
int tr[N];inline int lowbit(int x){return x&(-x);}
inline void add(int i,int x){for(;i<=n;i+=lowbit(i)) tr[i]+=x;}
inline int ask(int i){int res=0;for(;i;i-=lowbit(i)) res+=tr[i];return res;}
}tmp,t;
inline int LCP(int x,int y){return lcp.ask(x,y);}
inline int LCS(int x,int y){return lcs.ask(n-y+1,n-x+1);}
int sa[N],id[N];
vector < pii > v[N],g[N];
int main(){
cin>>cas>>n>>m>>s;s=' '+s;
lcp.Suffix_Sort();lcp.getheight();lcp.init();reverse(s.begin()+1,s.end());
lcs.Suffix_Sort();lcs.getheight();lcs.init();reverse(s.begin()+1,s.end());
for(int i=1,p,r;i<=m;++i){
cin>>p>>r;
v[p].emplace_back(r,i);
g[r].emplace_back(p,i);
}
for(int i=1;i<=n;++i) sa[i]=lcp.sa[i];
for(int i=n;i;--i){
for(auto x:v[sa[i]]) ans[x.sec]+=tmp.ask(sa[i]+x.fi)-tmp.ask(sa[i]);
tmp.add(sa[i],1);
}
for(int k=1;k<=n;++k){
for(int i=k;i+k<=n;i+=k){
int j=i+k;
int L=i-LCS(i,j)+1;
int R=j+LCP(i,j)-1;
if((R-j+1)+(i-L+1)<k) continue;
if(flag[L]==k||R-L+1<2*k) continue;
if(R==n||s[R-k+1]>s[R+1]) continue;
t.add(L,1);t.add(R-2*k+2,-1);
flag[L]=k;
}
for(auto x:g[k]) ans[x.sec]-=t.ask(x.fi);
}
for(int i=1;i<=m;++i) cout<<ans[i]<<'\n';
return 0;
}