[八省联考 2018] 制胡窜 题解
比较套路纸糊船题。
看到这种判断一个串是否出现在一个区间里的,直接想 SA 或者 SAM。但萌新不会 SAM,只能用 SA 硬上。
起手容斥,对于一个询问
发现只有带
应用 品酒大会 那道题的套路,将询问离线,倒序枚举
记
不包含
记
假设现在要求
假设总共有
没卡常,目前你谷第 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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】