P3732 [HAOI2017] 供给侧改革
题意
给一个长度为 \(n\) 的 \(01\) 串串,定义 \(\text{date}(l,r)\) 为起始位置在 \([L,R]\) 之间的这些后缀之中,具有最长公共前缀的两个后缀的最长公共前缀的长度。
给 \(q\) 次询问 \((L,R)\),表示求 \(ans=\sum_{L\le i<R}\text{data(i,R)}\)。
\(n,q\le10^5\)。
思路
先考虑对于制定的 \(L,R\),如何求 \(\text{data}(L,R)\)。
由于字符串随机生成,所以两个相同的字串不会太长。设 \(max\_len=32\),即最长的公共前缀不会超过 \(max\_len\)
对于每个位置 \(i\),求出祂向后 \(j(1\le j\le max\_len)\) 个字符的哈希值,记位 \(h_{i,j}\),求出最小的 \(nt_{i,j}\),满足 \(h_{nt_{i,j},j}=h_{i,j},nt_{i,j}>i\),如果没有,设为 \(n+1\)。
在求 \(\text{date}(L,R)\) 时,找到最大的长度 \(l\),满足 \(\min_{L\le i\le R}(nt_{i,l})<=R\),那么 \(\text{data}(L,R)=l\)。
对于一次询问 \((L,R)\),从小到大枚举一个长度 \(l\),求出最大的 \(i\),满足 \(nt_{i,l}\le R\),令 \(i'\) 是最大的满足 \(nt_{i',l-1}\le R\) 的位置,那么所有 \(j\in(i,i']\) 的贡献都是 \(l-1\)。
这个东西可以用线段树做。
时间复杂度 \(\mathcal O(n\log^2n)\)
代码
存哈希值是用 map 被卡常了,换了 unordered_map。
拿下最劣解。
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
#define ull unsigned long long
const int maxn=100010,maxlen=50;
int n,q,nt[maxn][maxlen];
string s;
class Hash{
private:
ull h[maxn],mi[maxn];
const ull base=131;
public:
void build(string s){
mi[0]=1;
for(int i=1;i<=100000;i++) mi[i]=mi[i-1]*base;
for(int i=0;i<s.size();i++) h[i+1]=h[i]*base+s[i]-'0';
}
ull query(int l,int r){return h[r]-h[l-1]*mi[r-l+1];}
}h;
unordered_map<ull,int>mp[maxlen];
class Segment_Tree{
private:
int t[maxn*4];
void insert(int u,int l,int r,int d,int z){
if(l>d||r<d) return ;
if(l==r){t[u]=z;return ;}
int mid=l+r>>1;
if(mid>=d) insert(u<<1,l,mid,d,z);
else insert(u<<1|1,mid+1,r,d,z);
t[u]=min(t[u<<1],t[u<<1|1]);
}
int query(int u,int l,int r,int ll,int rr,int x){
if(l>rr||r<ll) return -1;
if(l==r) return l;
int mid=l+r>>1;
if(t[u<<1|1]<=x) return query(u<<1|1,mid+1,r,ll,rr,x);
if(t[u<<1]<=x) return query(u<<1,l,mid,ll,rr,x);
return -1;
}
public:
void init(){memset(t,0x3f,sizeof(t));}
void insert(int d,int z){insert(1,1,n,d,z);}
int query(int l,int r,int x){return query(1,1,n,l,r,x);}
}t[maxlen];
signed main(){
for(int i=1;i<=32;i++) t[i].init();
read(n,q,s);
h.build(s);
for(int i=n;i>=1;i--){
nt[i][0]=i;
for(int j=1;j<=32;j++) nt[i][j]=n+1;
for(int j=1;j<=32;j++){
if(i+j-1>n) break;
ull ha=h.query(i,i+j-1);
if(mp[j][ha]) nt[i][j]=mp[j][ha];
mp[j][ha]=i;
}
}
for(int i=1;i<=n;i++) for(int j=1;j<=32;j++) t[j].insert(i,nt[i][j]);
for(int i=1;i<=q;i++){
int L,R;read(L,R);
int ans=0;
for(int l=1;l<=32;l++){
int w=t[l].query(L,R-1,R);
if(w!=-1) ans+=w-L+1;
}
write(ans),write("\n");
}
return 0;
}

浙公网安备 33010602011771号