把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF590E Birthday

题面传送门
陈指导一个小时写完的东西我写了四个小时。
也算是对AC自动机和最大独立集有了更深刻的了解。
首先子串关系想到AC自动机可以做。
具体的只要把每个前缀的结尾往上跳跳到第一个其它串的结尾即可。
然后floyd传递闭包一下即可。
但是问题是如果真的暴力跳是\(O(n\times \sum\limits{|S|})\)的。
然而这个东西在算fail指针的时候可以很好地算出来。
之后跑最大独立集即可。
很神奇的时间复杂度瓶颈居然在floyd和AC自动机上。复杂度\(O(\sum\limits{|S|}+\frac{n^3}{w})\)
code:

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define S 10000000
#define N 800
using namespace std;
int n,len,st,t,d[N+5<<1],nows[N+5<<1],fl[N+5<<1],ans,now,un,wn;bitset<N+5> dis[N+5];
char c[S+5];vector<int> pl[N+5];queue<int> q;
struct AC{
	int son[S+5][2],fail[S+5],val[S+5],cnt,now,i,pus;
	I void insert(int id){for(i=1,now=0;i<=len;i++) !son[now][c[i]-'a']&&(son[now][c[i]-'a']=++cnt),now=son[now][c[i]-'a'],pl[id].push_back(now);val[now]=id;}
	I void make(){
		for(i=0;i<=1;i++) son[0][i]&&(q.push(son[0][i]),0);val[0]=-1;
		while(!q.empty()){
			now=q.front();q.pop();!val[now]&&(val[now]=val[fail[now]]);
			for(i=0;i<=1;i++)!son[now][i]?(son[now][i]=son[fail[now]][i]):(q.push(son[now][i]),fail[son[now][i]]=son[fail[now]][i]);
		}
	}
	I void find(int id){for(i=0;i<pl[id].size();i++)now=pl[id][i],val[now]==id&&(now=fail[now]),~val[now]&&(dis[id][val[now]]=1);}
}g;
struct yyy{int to,w,z;}tmp;
struct ljb{
	int head,h[N+5<<1];yyy f[N*N+5<<1];
	I void add(int x,int y,int z){f[head]=(yyy){y,z,h[x]};h[x]=head++;}
}s;
I void get(int x,int y,int z){s.add(x,y,z);s.add(y,x,0);/*printf("%d %d\n",x,y);*/}
I int bfs(){
	memset(d,0x3f,sizeof(d));memset(nows,-1,sizeof(nows));while(!q.empty()) q.pop();q.push(st);d[st]=0;nows[st]=s.h[st];
	while(!q.empty()){
		now=q.front();q.pop();
		for(int i=s.h[now];~i;i=tmp.z){
			tmp=s.f[i];if(tmp.w&&d[tmp.to]>=1e9){
				d[tmp.to]=d[now]+1;nows[tmp.to]=s.h[tmp.to];q.push(tmp.to);
				if(tmp.to==t) return 1;
			} 
		}
	}
	return 0;
}
I int dfs(int x,int sum){
	if(x==t) return sum;yyy tmp;int k,pus=0;
	for(int i=s.h[x];~i;i=tmp.z){
		tmp=s.f[i];
		if(tmp.w&&d[tmp.to]==d[x]+1){
			k=dfs(tmp.to,min(tmp.w,sum));if(!k) d[tmp.to]=1e9;
			pus+=k;sum-=k;s.f[i].w-=k;s.f[i^1].w+=k;
		}
		if(!sum) break;
	}
	return pus;
}
I void check(int x){
	if(fl[x]||x==t||x==st) return;fl[x]=1;yyy tmp;
	for(int i=s.h[x];~i;i=tmp.z)  tmp=s.f[i],!tmp.w&&(check(tmp.to),0);
} 
int main(){
	freopen("1.in","r",stdin);freopen("1.out","w",stdout);
	re int i,j,k;scanf("%d",&n);st=0;t=2*n+1;memset(s.h,-1,sizeof(s.h));
	for(i=1;i<=n;i++) scanf("%s",c+1),len=strlen(c+1),g.insert(i);
	g.make();for(i=1;i<=n;i++) g.find(i);
	for(i=1;i<=n;i++) get(0,i,1),get(i+n,t,1);
	for(k=1;k<=n;k++){
		for(i=1;i<=n;i++)dis[i][k]&&(dis[i]|=dis[k],0);
	}
	for(i=1;i<=n;i++){
		for(j=1;j<=n;j++) i^j&&dis[i][j]&&(get(i,j+n,1),0);
	}
	while(bfs()) ans+=dfs(st,1e9);printf("%d\n",n-ans);
	for(i=s.h[t];~i;i=tmp.z) tmp=s.f[i],!tmp.w&&(check(tmp.to),0);
	for(i=1;i<=n;i++) if(!(fl[i]|(fl[i+n]^1))) printf("%d ",i);
} 
posted @ 2021-05-08 22:43  275307894a  阅读(50)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end