题解 字符串
小清新神奇题目
选一个前缀和一个后缀拼起来,求出现次数?
发现出现位置满足前缀出现了后缀也出现了
发现就是正反串 border 出现过的位置交
建成 border 树变为子树交,然后树状数组扫描线即可
复杂度 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 400010
#define fir first
#define sec second
#define pb push_back
#define ll long long
#define ull unsigned long long
//#define int long long
int n, q;
char s[N];
int x[N], y[N];
namespace force{
bool vis[N];
ull pw[N], h[N];
const ull base=13131;
unordered_map<ull, int> mp;
inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
void solve() {
pw[0]=1; mp.clear();
for (int i=1; i<=n; ++i) vis[i]=0;
for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base;
for (int i=1; i<=n; ++i) h[i]=h[i-1]*base+s[i];
for (int i=1,x,y; i<=q; ++i) {
x=::x[i], y=::y[i];
ull tem=h[x]*pw[y]+hashing(n-y+1, n);
int len=x+y;
if (!vis[len]) {
vis[len]=1;
for (int j=1; j+len-1<=n; ++j) ++mp[hashing(j, j+len-1)];
}
printf("%d\n", mp[tem]);
}
}
}
namespace task1{
int len[N], fail[N], tr[N][26], right[N], tem[N], cnt[N], pos[N], now, tot;
void init() {fail[now=tot=0]=-1; memset(tr, 0, sizeof(tr)); memset(cnt, 0, sizeof(cnt));}
void insert(char c) {
c-='a';
int cur=++tot;
len[cur]=len[now]+1;
int p, q;
for (p=now; ~p&&!tr[p][c]; tr[p][c]=cur,p=fail[p]);
if (p==-1) fail[cur]=0;
else if (len[q=tr[p][c]]==len[p]+1) fail[cur]=q;
else {
int cln=++tot;
len[cln]=len[p]+1;
fail[cln]=fail[q];
for (; ~p&&tr[p][c]==q; tr[p][c]=cln,p=fail[p]);
for (int i=0; i<26; ++i) tr[cln][i]=tr[q][i];
fail[cur]=fail[q]=cln;
}
++right[now=cur];
pos[len[cur]]=cur;
}
void solve() {
init();
memset(right, 0, sizeof(right));
for (int i=1; i<=n; ++i) insert(s[i]);
for (int i=1; i<=tot; ++i) ++cnt[len[i]];
for (int i=1; i<=n; ++i) cnt[i]+=cnt[i-1];
for (int i=1; i<=tot; ++i) tem[cnt[len[i]]--]=i;
for (int i=tot; i; --i) right[fail[tem[i]]]+=right[tem[i]];
for (int i=1,x,y; i<=q; ++i) {
// cout<<"i: "<<i<<endl;
x=::x[i], y=::y[i];
int u=pos[x];
for (int j=1; j<=y; ++j)
if (!(u=tr[u][s[n-y+j]-'a'])) {puts("0"); goto jump;}
printf("%d\n", right[u]);
jump: ;
}
}
}
namespace task{
vector<int> to1[N], to2[N];
vector<pair<int, int>> que[N];
int nxt[N], ans[N], id[N], siz[N], bit[N], tot;
inline void add(int i, int dat) {for (; i<=tot; i+=i&-i) bit[i]+=dat;}
inline int query(int l, int r) {
// cout<<"query: "<<l<<' '<<r<<endl;
int ans=0; --l;
while (r>l) ans+=bit[r], r-=r&-r;
while (l>r) ans-=bit[l], l-=l&-l;
return ans;
}
void dfs2(int u) {
// cout<<"dfs2: "<<u<<endl;
siz[u]=1; id[u]=++tot;
// cout<<id[u]<<endl;
for (auto v:to2[u]) dfs2(v), siz[u]+=siz[v];
}
void dfs1(int u) {
// cout<<"dfs1: "<<u<<endl;
for (auto it:que[u]) ans[it.sec]-=query(id[it.fir], id[it.fir]+siz[it.fir]-1); //, cout<<"- "<<query(id[it.fir], id[it.fir]+siz[it.fir]-1)<<endl;
if (id[n-u]) add(id[n-u], 1); //, cout<<"at: "<<u<<" add "<<n-u<<endl;
for (auto v:to1[u]) dfs1(v);
for (auto it:que[u]) ans[it.sec]+=query(id[it.fir], id[it.fir]+siz[it.fir]-1); //, cout<<"+ "<<query(id[it.fir], id[it.fir]+siz[it.fir]-1)<<endl;
}
void solve() {
for (int i=1; i<=n; ++i) bit[i]=0; tot=0;
for (int i=0; i<=n; ++i) to1[i].clear(), to2[i].clear(), que[i].clear();
for (int i=1; i<=q; ++i) ans[i]=0;
to1[0].pb(1);
for (int i=2,j=0; i<=n; ++i) {
while (j && s[j+1]!=s[i]) j=nxt[j];
if (s[j+1]==s[i]) ++j;
nxt[i]=j;
to1[j].pb(i);
}
// cout<<"nxt: "; for (int i=1; i<=n; ++i) cout<<nxt[i]<<' '; cout<<endl;
reverse(s+1, s+n+1);
memset(nxt, 0, sizeof(nxt));
to2[0].pb(1);
for (int i=2,j=0; i<=n; ++i) {
while (j && s[j+1]!=s[i]) j=nxt[j];
if (s[j+1]==s[i]) ++j;
nxt[i]=j;
to2[j].pb(i);
}
// cout<<"nxt: "; for (int i=1; i<=n; ++i) cout<<nxt[i]<<' '; cout<<endl;
dfs2(0);
for (int i=1,x,y; i<=q; ++i) {
x=::x[i], y=::y[i];
que[x].pb({y, i});
}
dfs1(0);
for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
}
}
signed main()
{
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d%s", &n, &q, s+1);
bool same_sum=1;
for (int i=1; i<=q; ++i) {
scanf("%d%d", &x[i], &y[i]);
if (x[i]+y[i]!=n-1) same_sum=0;
}
// if (n<=2000||same_sum) force::solve();
// else task1::solve();
task::solve();
}
return 0;
}