[八省联考 2018] 制胡窜 题解
比较套路纸糊船题。
看到这种判断一个串是否出现在一个区间里的,直接想 SA 或者 SAM。但萌新不会 SAM,只能用 SA 硬上。
起手容斥,对于一个询问 \([l,r]\),记性质 \(A\) 表示其在 \([1,i]\) 中出现过,同理 \(B\) 表示其在 \([i+1,j-1]\) 中出现过,\(C\) 表示其在 \([j,n]\) 中出现过,记 \(P(M)\) 为满足 \(M\) 性质区间 \([i,j]\) 的个数。显然有
发现只有带 \(B\) 的难求,先不考虑这个,考虑如何求只有 \(A,C\) 的。
应用 品酒大会 那道题的套路,将询问离线,倒序枚举 \(len\),对于所有的 \(ht_i\ge len\) 的,将 \(sa_i\) 与 \(sa_{i-1}\) 连边,用并查集维护,那么现在所有与 \(S_{[l,r]}\) 相等的子串的起始位置都与 \(l\) 在同一连通块中。
记 \(s\) 表示 \(l\) 所在的连通块中的最小值,\(t\) 表示 \(l\) 所在的连通块中的最大值,\(len=r-l+1\)。那么就有 \(P(A)=\sum\limits_{i=s+len-1}^{n-2}\sum\limits_{j=i+2}^n1\),同理 \(P(B)=\sum\limits_{i=1}^{t-2}\sum\limits_{j=i+2}^t1\),\(P(C)=\sum\limits_{i=s+len-1}^{t-2}\sum\limits_{j=i+2}^t1\)。发现这些东西都是同构的,都是形如 \(\sum\limits_{i=s}^{t-2}\sum\limits_{j=i+2}^{t}\),那么记其为 \(f(s,t)\),直接等差数列就有 \(f(s,t)=(t-s)(t-s-1)/2\),注意如果当 \(s+2>t\) 时值为 \(0\)。
不包含 \(B\) 的考虑完了,考虑包含 \(B\) 的怎么做。
记 \(g(a,b)\) 表示 \(a\le i\And j\le b\),满足 \(B\) 性质的合法 \([i,j]\) 数,显然 \(P(B)=g(1,n)\),\(P(AB)=g(s+len-1,n)\),\(P(BC)=g(1,t)\),\(P(ABC)=g(s+len-1,t)\)。考虑如何求 \(g\)。
假设现在要求 \(g(a,b)\)。由于一个区间 \([i,j]\) 满足性质 \(B\) 当且仅当 \(l\) 所在的连通块中有一个数 \(x\in [i+1,j-1]\) 且 \(x+len-1\le b\),那么就求 \([a+1,b-len]\) 中与 \(l\) 在同一个连通块中的位置,考虑其贡献。
假设总共有 \(K\) 个位置满足上述性质,且第 \(i\) 个位置为 \(q_i\),钦定 \(q_0=a\),考虑枚举合法区间的第一个与 \([l,r]\) 相同的位置。显然有\(h(\alpha)=\sum\limits_{i=q_{\alpha-1}}^{q_{\alpha}-1}\sum\limits_{j=q_{\alpha}+len}^{b}1=(b-q_{\alpha}-len+1)(q_{\alpha}-q_{\beta})=(b-len+1)(q_{\alpha}-q_{\beta})-q_{\alpha}^2+q_{\alpha}q_{\beta}\),其中\(\beta=\alpha-1\),然后记其为 \(h(\alpha)\)。那么 \(g(a,b)=\sum\limits_{\alpha=1}^{K}h(\alpha)=(b-len+1)(q_K-a)+a\times q_1-\sum\limits_{\alpha=1}^Kq_{\alpha}^2+\sum\limits_{\alpha=2}^Kq_{\alpha}q_{\alpha-1}\)。第一项和第二项直接求最大值计算,后面两项用线段树维护即可。对于合并两个连通块,直接上线段树合并即可。
没卡常,目前你谷第 3 优解。代码有点细节。
code
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t;i += p)
#define drep(i,s,t,p) for(int i = s;i >= t;i -= p)
#ifdef LOCAL
auto I = freopen("in.in","r",stdin),O = freopen("out.out","w",stdout);
#else
auto I = stdin,O = stdout;
#endif
using ll = long long;using ull = unsigned long long;
using db = double;using ldb = long double;
#define ep emplace
const int N = 1e5 + 10;
vector<tuple<int,int,int> > Q[N];
int n,m;ll ans[N*3];
char s[N];int rk[N],ct[N],ht[N],sa[N],tp[N];
void Get_SA(){
int m = 10;
auto _G = [](char x){return x - '0' + 1;};
auto Qsort = [&](){
rep(i,1,m,1) ct[i] = 0;
rep(i,1,n,1) ct[rk[i]]++;
rep(i,1,m,1) ct[i] += ct[i-1];
drep(i,n,1,1) sa[ct[rk[tp[i]]]--] = tp[i];
};
rep(i,1,n,1) rk[i] = _G(s[i]),tp[i] = i;
Qsort();
for(int w = 1,p = 0;w <= n;w <<= 1,m = p,p = 0){
rep(i,n-w+1,n,1) tp[++p] = i;
rep(i,1,n,1) if(sa[i] > w) tp[++p] = sa[i] - w;
Qsort();rep(i,1,n,1) tp[i] = rk[i];
p = rk[sa[1]] = 1;
auto cmp = [&](int x,int y){return tp[x] == tp[y] && tp[x + w] == tp[y + w];};
rep(i,2,n,1) rk[sa[i]] = cmp(sa[i-1],sa[i])?p:++p;
if(p == n) break;
}
for(int i = 1,k = 0;i <= n; ++i){
if(k) --k;
int j = sa[rk[i]-1];
while(s[i + k] == s[j + k]) k++;
ht[rk[i]] = k;
}
}
int fa[N],rt[N];
int GF(int x){while(x ^ fa[x]) x = fa[x] = fa[fa[x]];return x;}
struct Segment_Tree{
struct node{
int ls,rs,mn,mx;
ll sum,val;
#define ls(x) t[x].ls
#define rs(x) t[x].rs
#define mn(x) t[x].mn
#define mx(x) t[x].mx
#define sum(x) t[x].sum
#define val(x) t[x].val
}t[N*30];
using tpl = tuple<int,int,ll,ll>;
#define mt make_tuple
int tot;
Segment_Tree(){t[0].mn = 0;tot = 0;}
void P(int p,int q){val(p) = val(q);sum(p) = sum(q);mn(p) = mn(q),mx(p) = mx(q);}
void U(int p){
if(!ls(p) && !rs(p)) return;
if(!ls(p)) return P(p,rs(p));
if(!rs(p)) return P(p,ls(p));
val(p) = val(ls(p)) + val(rs(p)) + 1ll*mx(ls(p))*mn(rs(p));
sum(p) = sum(ls(p)) + sum(rs(p));
mn(p) = min(mn(ls(p)),mn(rs(p)));
mx(p) = max(mx(ls(p)),mx(rs(p)));
}
void C(int &now,int p,int l = 1,int r = n){
if(!now) now = ++tot;
if(l == r) return val(now) = 0,mn(now) = mx(now) = p,sum(now) = 1ll*p*p,void();
int mid = (l + r) >> 1;
p <= mid?C(ls(now),p,l,mid):C(rs(now),p,mid+1,r);
U(now);
}
#define A(i,x) (get<i>(x))
tpl U(const auto &x,const auto &y){
return mt(min(A(0,x),A(0,y)),max(A(1,x),A(1,y)),A(2,x)+A(2,y),A(3,x)+A(3,y)+(A(0,y)==1e9?0ll:1ll*A(1,x)*A(0,y)));
}
tpl Q(int now,int ql,int qr,int l = 1,int r = n){
if(!now) return mt(1e9,0,0,0);
if(ql <= l && r <= qr) return mt(mn(now),mx(now),sum(now),val(now));
int mid = (l + r) >> 1;
if(ql > mid) return Q(rs(now),ql,qr,mid+1,r);
else if(qr <= mid) return Q(ls(now),ql,qr,l,mid);
else return U(Q(ls(now),ql,qr,l,mid),Q(rs(now),ql,qr,mid+1,r));
}
void M(int &x,const int &y,int l = 1,int r = n){
if(!x) return x = y,void();
if(!y) return;
int mid = (l + r) >> 1;
M(ls(x),ls(y),l,mid);M(rs(x),rs(y),mid+1,r);
U(x);
}
}sgt;
void Merge(int x,int y){
if(!x || !y) return;
x = GF(x),y = GF(y);
if(x == y) return;
fa[x] = y;sgt.M(rt[y],rt[x]);
}
void Work(){
auto f = [](int n,int m){return n + 2 > m?0ll:1ll*(m-n)*(m-n-1)/2;};
auto g = [&](int a,int b,int len,int x){
if(a + 1 > b-len) return 0ll;
ll res = 0;
auto [q1,qk,sum,val] = sgt.Q(rt[x],a+1,b-len);
if(!qk) return 0ll;
res += 1ll*(qk-a)*(b-len+1) + 1ll*a*q1;
res -= sum-val;
return res;
};
vector<pair<int,int> > vec;
rep(i,1,n,1) vec.emplace_back(ht[i],i);
sort(vec.begin(),vec.end(),greater<>());
int now = -1,siz = (int) vec.size() - 1;
drep(len,n,1,1){
if(Q[len].empty()) continue;
while(now < siz && vec[now + 1].first >= len) now++,Merge(sa[vec[now].second],sa[vec[now].second-1]);
for(const auto &[l,r,id]:Q[len]){
ll res = 0;int x = GF(l);
int s = sgt.t[rt[x]].mn,t = sgt.t[rt[x]].mx;
res += f(s+len-1,n);res += f(1,t);res -= f(s+len-1,t);
res += g(1,n,len,x);res -= g(s+len-1,n,len,x);
res += g(s+len-1,t,len,x);res -= g(1,t,len,x);
ans[id] = res;
}
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
cin>>n>>m>>(s + 1);
rep(i,1,n,1) fa[i] = i,sgt.C(rt[i],i);
for(int i = 1,l,r;i <= m; ++i){
cin>>l>>r;
if(l == r) ans[i] = 1ll*(n-1)*(n-2)/2;
else if(r - l + 1 >= n - 1) ans[i] = 0;
else Q[r-l+1].emplace_back(l,r,i);
}
Get_SA();Work();
rep(i,1,m,1) cout<<ans[i]<<'\n';
}
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18736898