CF587F Duff is Mad
直接做没什么思路,那就考虑根号算法
令 $\mathrm{s[k]}$ 的长度为 $\mathrm{len}$.
如果 $\mathrm{len}$ 的长度大于根号 $\mathrm{n}$, 则这样的 $\mathrm{s[k]}$ 很少.
可以直接枚举长度大于根号的串,然后和其他所有串去匹配.
具体方法就是建出所有串的 AC 自动机,然后标记上长串的所有节点.
枚举其他所有串,每次做一个子树查询(DFS序上的区间查询)
由于更新次数为 $O(n)$, 直接做一个前缀和,不用数据结构.
对于 $\mathrm{s[k]}$ 串很短的情况,直接暴力枚举左端点,然后向右移动右端点.
建一个 $\mathrm{trie}$ 树然后二分位置就完事了.
块的大小取 300 左右差不多能过.
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <cstring>
#include <algorithm>
#define B 350
#define N 100009
#define pb push_back
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
struct BIT {
int C[N];
void upd(int x, int v) {
C[x]+=v;
}
void upd() {
for(int i=1;i<100009;++i) C[i] += C[i-1];
}
int query(int x) {
return C[x];
}
void clr() {
for(int i=0;i<100009;++i) C[i]=0;
}
int Q(int l,int r) {
if(l>r) return 0;
return query(r)-query(l-1);
}
}T;
char str[N];
queue<int>que;
vector<int>ss[N],G[N],ind[N];
int n,Q,cnt,tot,scc, nod,re[N];
int id[N],fin[N],ch[N][26],fail[N],st[N],ed[N],c2[N][26];
ll f[250+2][100009];
void dfs(int x) {
st[x]=++scc;
for(int i=0;i<G[x].size();++i) {
dfs(G[x][i]);
}
ed[x]=scc;
}
void build() {
for(int i=0;i<26;++i) {
if(ch[0][i]) {
fail[ch[0][i]]=0;
que.push(ch[0][i]);
}
}
while(!que.empty()) {
int u=que.front(); que.pop();
for(int i=0;i<26;++i) {
int q=ch[u][i];
if(!q) {
ch[u][i]=ch[fail[u]][i];
continue;
}
fail[q]=ch[fail[u]][i];
que.push(q);
}
}
for(int i=1;i<=tot;++i) {
G[fail[i]].pb(i);
}
dfs(0);
}
void calcf() {
for(int i=1;i<=cnt;++i) {
int o=re[i],rt=0;
for(int j=1;j<ss[o].size();++j) {
rt=ch[rt][ss[o][j]];
T.upd(st[rt], +1);
}
T.upd();
for(int j=1;j<=n;++j) {
int p=fin[j];
f[i][j]=(ll)T.Q(st[p], ed[p])+f[i][j-1];
}
T.clr();
}
}
int main() {
// setIO("input");
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i) {
scanf("%s",str+1);
int p=strlen(str+1);
ss[i].pb(0);
for(int j=1;j<=p;++j) {
ss[i].pb(str[j]-'a');
}
// 大于等于 B 的编号.
if(p >= B)
re[id[i] = ++ cnt] = i;
int rt=0;
for(int j=1;j<=p;++j) {
if(!ch[rt][str[j] - 'a'])
ch[rt][str[j] - 'a'] = ++tot;
rt=ch[rt][str[j] - 'a'];
}
fin[i] = rt;
if(p < B) {
rt=0;
for(int j=1;j<=p;++j) {
if(!c2[rt][str[j] - 'a']) {
c2[rt][str[j] - 'a'] = ++nod;
}
rt = c2[rt][str[j] - 'a'];
}
ind[rt].pb(i);
}
}
// 建立完 AC 自动机.
build(),calcf();
for(int i=1;i<=Q;++i) {
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
ll ans = 0ll;
if(id[k]) {
ans += (ll)(f[id[k]][r] - f[id[k]][l-1]);
}
if(ss[k].size() - 1 < B) {
for(int j=1;j<ss[k].size();++j) {
int rt=c2[0][ss[k][j]];
for(int h=j;h<ss[k].size();++h) {
if(!rt) {
break;
}
// 处理到 h=1;
if(ind[rt].size()) {
int L=lower_bound(ind[rt].begin(), ind[rt].end(), l)-ind[rt].begin();
int R=lower_bound(ind[rt].begin(), ind[rt].end(), r+1)-ind[rt].begin();
// [L, R)
if(R>L) {
ans += (ll)(R - L);
}
}
if(h == ss[k].size() - 1) break;
rt = c2[rt][ss[k][h + 1]];
}
}
}
printf("%lld\n", ans);
}
return 0;
}

浙公网安备 33010602011771号