专栏文章

题解:P8203 [传智杯 #4 决赛] DDOSvoid 的馈赠

P8203题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mind3c60
此快照首次捕获于
2025/12/02 00:26
3 个月前
此快照最后确认于
2025/12/02 00:26
3 个月前
查看原文

前言

为了纪念我 csp2025 的 t3。

思路

首先我们可以发现 n105n\leq 10^5 然后题目又求的是 tx,tyt_x,t_y 的共同的被包含字串 sis_i 的个数,那么我们可以往 bitset 上想,如果我们能维护出相对 txt_x 合法的串并存入 bitset 中我们就可以做到 nqw\frac{nq}{w} 的复杂度,但是由于空间炸了所以考虑分块做我们对 sis_i 分块,然后 bitset 的空间就降到了 Bnw\frac{Bn}{w} 的,然后我们就做完了,我们每 BB 个分一组,插入 ACAM 中然后建出 fail 树求出每个点的合法点集之后我们遍历每一个 tit_i 并求出其合法点集,查询时直接求并然后将个数加入答案即可。

代码

CPP
#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define rep1(i,x,y) for(register int i=x;i>=y;--i)
#define int long long
#define fire signed
#define il inline
template<class T> il void print(T x) {
	if(x<0) printf("-"),x=-x;
	if (x > 9) print(x / 10);
	putchar(x % 10 + '0');
}
template<class T> il void in(T &x) {
    x = 0; char ch = getchar();
    int f = 1;
    while (ch < '0' || ch > '9') {if(ch=='-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
    x *= f;
}
int T=1;
const int N=1e5+10,M=333;
bitset<M>f[N],g[N];
struct node{
	int fl;
	int s[30];
}tr[N];
vector<int>v[N];
int vis[N];
int idx=1;
vector<int>ve[N];
void modify(string s,int id) {
	int p=1;
	for(auto to:s) {
		if(!tr[p].s[to-'a']) tr[p].s[to-'a']=++idx;
		p=tr[p].s[to-'a'];
	}
	ve[p].pb(id);
}
void get() {
	queue<int>q;
	rep(i,0,25) tr[0].s[i]=1;
	q.push(1);
	while(q.size())  {
		int x=q.front(),f=tr[x].fl;
		q.pop();
		rep(i,0,25) {
			int &v=tr[x].s[i];
			if(v) {
				q.push(v);
				tr[v].fl=tr[f].s[i];
			}else v=tr[f].s[i];
		}
	}
}
int n,m,q;
string s[N],t[N];
int x[N],y[N],ans[N],bl[N],ll[N],rr[N];
void dfs(int x,int fa) {
	for(auto to:ve[x]) f[x][to]=1;
	for(auto to:v[x]) {
		if(to==fa) continue;
		f[to]|=f[x];
		dfs(to,x);
	}
}
void solve() {
	in(n),in(m),in(q);
	int len=sqrt(n);
	rep(i,1,n) cin>>s[i],bl[i]=(i-1)/len+1;
	rep(i,1,n) {
		if(!ll[bl[i]]) ll[bl[i]]=i;
		rr[bl[i]]=i;
	}
	rep(i,1,m) {
		cin>>t[i];
	}
	rep(i,1,q) in(x[i]),in(y[i]);
	vis[1]=-1;
	rep(i,1,bl[n]) {
		idx=1;
		rep(j,ll[i],rr[i]) {
			modify(s[j],j-ll[i]);
		}
		get();
		rep(j,1,idx) v[tr[j].fl].pb(j);
		dfs(1,0);
		rep(j,1,m) {
			int p=1;
			g[j].reset();
			for(auto to:t[j]) {
				p=tr[p].s[to-'a'];
				g[j]|=f[p];
			}
		}
		rep(j,1,q) {
			ans[j]+=(g[x[j]]&g[y[j]]).count();
		}
		rep(j,1,idx) f[j].reset(),v[j].clear(),ve[j].clear();
		rep(j,1,idx) rep(x,0,25) tr[j].s[x]=tr[j].fl=0;
	}
	rep(i,1,q) printf("%lld\n",ans[i]);
}
fire main() {
	while(T--) {
		solve();
	}
	return false;
}
为啥我 csp 之前不会 ACAM 啊,/ll。

评论

2 条评论,欢迎与作者交流。

正在加载评论...