题解 [CF590E] Birthday
首先……怎么找出所有串之间的包含关系呢?
这个人太弱了只会根号找
所以当他赛后听说用 AC 自动机可以 \(O(\sum len)\) 的时候整个人傻掉了(
考虑对 AC 自动机上每个节点维护从这个点向上跳能跳到的第一个结束节点
然后这个东西可以在建 AC 自动机的时候处理出来
于是可以建立偏序关系
然后再跑一个传递闭包就可以建出完整的图了
然后就是 Dilworth 定理输出方案了,与 [CTSC2008]祭祀 是相同的
复杂度 \(O(m)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1510
#define M 10000010
#define pb push_back
#define ll long long
#define ull unsigned long long
//#define int long long
int n;
string s[N];
// ull pw[10000010];
// const ull base=13131;
int uni[N], usiz, sum, max_len;
// namespace force{
// ull h[N];
// int ans, rec;
// unordered_map<ull, bool> mp;
// inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
// void solve() {
// int lim=1<<n;
// for (int s=0; s<lim; ++s) {
// mp.clear();
// for (int i=1; i<=n; ++i) if (s&(1<<i-1)) {
// ull h=0;
// for (auto it:(::s[i])) h=h*base+it;
// // if (s==7) cout<<"add: "<<i<<' '<<h<<endl;
// mp[h]=1;
// }
// for (int i=1; i<=n; ++i) if (s&(1<<i-1)) {
// // if (s==7) cout<<"i: "<<i<<endl;
// for (int j=1; j<=::s[i].length(); ++j) h[j]=h[j-1]*base+::s[i][j-1];
// for (int l=1; l<=::s[i].length(); ++l)
// for (int r=l; r<=::s[i].length(); ++r)
// if (!(l==1&&r==::s[i].length()) && mp.find(hashing(l, r))!=mp.end())
// goto jump;
// }
// if (__builtin_popcount(s)>ans) ans=__builtin_popcount(s), rec=s;
// jump: ;
// }
// cout<<ans<<endl;
// for (int i=1; i<=n; ++i) if (rec&(1<<i-1)) cout<<i<<' '; cout<<endl;
// }
// }
// namespace task1{
// ull h[10000010];
// vector<int> to[N];
// bool vis[1010][1010];
// unordered_map<ull, int> mp;
// int head[N], dep[N], cur[N], sta[N], ecnt=1, s, t, tot, ans, top;
// struct edge{int to, next, val;}e[N<<1];
// inline void add(int s, int t, int w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}
// inline ull hashing(int l, int r) {return h[r]-h[l-1]*pw[r-l+1];}
// void build() {
// for (int i=1; i<=n; ++i) {
// ull h=0;
// for (auto it:(::s[i])) h=h*base+it;
// mp[h]=i;
// }
// for (int i=1,len; i<=n; ++i) {
// len=::s[i].length();
// for (int j=1; j<=len; ++j) h[j]=h[j-1]*base+::s[i][j-1];
// for (int j=1; j<=usiz; ++j) if (uni[j]<len) {
// for (int l=1; l+uni[j]-1<=len; ++l) {
// ull tem=hashing(l, l+uni[j]-1);
// if (mp.find(tem)!=mp.end() && !vis[i][mp[tem]]) to[i].pb(mp[tem]), vis[i][mp[tem]]=1; //, cout<<"link: "<<i<<' '<<mp[tem]<<endl;
// }
// }
// }
// }
// bool bfs(int s, int t) {
// for (int i=1; i<=tot; ++i) dep[i]=0;
// queue<int> q;
// dep[s]=1; cur[s]=head[s];
// q.push(s);
// while (q.size()) {
// int u=q.front(); q.pop();
// for (int i=head[u],v; ~i; i=e[i].next) {
// v = e[i].to;
// if (e[i].val&&!dep[v]) {
// dep[v]=dep[u]+1;
// cur[v]=head[v];
// if (v==t) return 1;
// q.push(v);
// }
// }
// }
// return 0;
// }
// int dfs(int u, int in) {
// if (u==t||!in) return in;
// int rest=in, tem;
// for (int i=cur[u],v; ~i; cur[u]=i=e[i].next) {
// v = e[i].to;
// if (e[i].val&&dep[v]==dep[u]+1) {
// tem=dfs(v, min(rest, e[i].val));
// if (!tem) dep[v]=0;
// rest-=tem;
// e[i].val-=tem;
// e[i^1].val+=tem;
// if (!rest) break;
// }
// }
// return in-rest;
// }
// void force_solve() {
// int lim=1<<n, ans=0, rec=0;
// bool vis[25];
// for (int s=0; s<lim; ++s) {
// for (int i=1; i<=n; ++i)
// if (s&(1<<i-1)) vis[i]=1;
// else vis[i]=0;
// for (int i=1; i<=n; ++i) if (s&(1<<i-1))
// for (auto v:to[i]) if (vis[v]) goto jump;
// if (__builtin_popcount(s)>ans) ans=__builtin_popcount(s), rec=s;
// jump: ;
// }
// cout<<ans<<endl;
// for (int i=1; i<=n; ++i) if (rec&(1<<i-1)) cout<<i<<' '; cout<<endl;
// exit(0);
// }
// void solve() {
// build();
// if (n<=20) force_solve();
// memset(head, -1, sizeof(head));
// s=2*n+1, t=2*n+2, tot=2*n+2;
// for (int u=1; u<=n; ++u)
// for (auto v:to[u])
// add(u, v+n, 1), add(v+n, u, 0);
// for (int i=1; i<=n; ++i) {
// add(s, i, 1), add(i, s, 0);
// add(i+n, t, 1), add(t, i+n, 0);
// }
// while (bfs(s, t)) ans+=dfs(s, INF);
// printf("%d\n", n-ans);
// for (int u=n+1; u<=2*n; ++u)
// for (int i=head[u],v; ~i; i=e[i].next)
// if (e[i].to==t&&e[i].val)
// sta[++top]=u-n;
// sort(sta+1, sta+top+1);
// for (int i=1; i<=top; ++i) for (int j=1; j<=top; ++j) if (vis[sta[i]][sta[j]]) goto jump;
// for (int i=1; i<=top; ++i) printf("%d%c", sta[i], " \n"[i==top]);
// return ; jump: top=0;
// for (int i=head[s],v; ~i; i=e[i].next) if (e[i].val) sta[++top]=e[i].to;
// sort(sta+1, sta+top+1);
// for (int i=1; i<=top; ++i) printf("%d%c", sta[i], " \n"[i==top]);
// }
// }
namespace task{
bool vis[N];
queue<int> q;
bitset<N> mask[N];
vector<int> to[N], sta;
int tr[M][2], fail[M], top[M], tot;
int head[N], dep[N], cur[N], ecnt=1, s, t, ans;
struct edge{int to, next, val;}e[N*N*2];
inline void add(int s, int t, int w) {e[++ecnt]={t, head[s], w}; head[s]=ecnt;}
void ins(string& s, int id) {
for (int p=0,*t,i=0; ; p=*t,++i) {
t=&tr[p][s[i]-'a'];
if (!*t) *t=++tot;
if (i+1==s.length()) {top[*t]=id; return ;}
}
}
void build() {
for (int i=1; i<=n; ++i) ins(::s[i], i);
int u=0;
for (int i=0; i<2; ++i)
if (tr[u][i]) fail[tr[u][i]]=u, q.push(tr[u][i]);
else tr[u][i]=u;
while (q.size()) {
u=q.front(); q.pop();
for (int i=0; i<2; ++i)
if (tr[u][i]) {
fail[tr[u][i]]=tr[fail[u]][i], q.push(tr[u][i]);
if (!top[tr[u][i]]) top[tr[u][i]]=top[fail[tr[u][i]]];
}
else tr[u][i]=tr[fail[u]][i];
}
for (int i=1; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
for (int p=0,j=0; ; p=tr[p][::s[i][j++]-'a']) {
// cout<<"j: "<<j<<' '<<top[p]<<endl;
if (top[p]&&top[p]!=i) mask[i][top[p]]=1;
if (j==::s[i].length()) {
if (top[fail[p]]) mask[i][top[fail[p]]]=1;
break;
}
}
}
// cout<<"---e---"<<endl; for (int i=1; i<=n; ++i) {for (int j=1; j<=n; ++j) cout<<mask[i][j]<<' '; cout<<endl;}
for (int k=1; k<=n; ++k)
for (int i=1; i<=n; ++i) if (mask[i][k])
mask[i]|=mask[k];
for (int i=1; i<=n; ++i)
for (int j=1; j<=n; ++j) if (mask[i][j])
to[i].pb(j); //, cout<<"link: "<<i<<' '<<j<<endl;
}
bool bfs(int s, int t) {
for (int i=1; i<=tot; ++i) dep[i]=0;
queue<int> q;
dep[s]=1; cur[s]=head[s];
q.push(s);
while (q.size()) {
int u=q.front(); q.pop();
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (e[i].val&&!dep[v]) {
dep[v]=dep[u]+1;
cur[v]=head[v];
if (v==t) return 1;
q.push(v);
}
}
}
return 0;
}
int dfs(int u, int in) {
if (u==t||!in) return in;
int rest=in, tem;
for (int i=cur[u],v; ~i; cur[u]=i=e[i].next) {
v = e[i].to;
if (e[i].val&&dep[v]==dep[u]+1) {
tem=dfs(v, min(rest, e[i].val));
if (!tem) dep[v]=0;
rest-=tem;
e[i].val-=tem;
e[i^1].val+=tem;
if (!rest) break;
}
}
return in-rest;
}
void dfs(int u) {
vis[u]=1;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v!=s&&v!=t&&!e[i].val&&!vis[v]) dfs(v);
}
}
void solve() {
build();
memset(head, -1, sizeof(head));
s=2*n+1, t=2*n+2, tot=2*n+2;
for (int u=1; u<=n; ++u)
for (auto v:to[u])
add(u, v+n, 1), add(v+n, u, 0);
for (int i=1; i<=n; ++i) {
add(s, i, 1), add(i, s, 0);
add(i+n, t, 1), add(t, i+n, 0);
}
while (bfs(s, t)) ans+=dfs(s, INF);
printf("%d\n", n-ans);
for (int u=n+1; u<=2*n; ++u)
for (int i=head[u],v; ~i; i=e[i].next)
if (e[i].to==t && e[i].val)
dfs(u);
for (int i=1; i<=n; ++i) if (!(vis[i]||!vis[i+n])) sta.pb(i);
sort(sta.begin(), sta.end());
for (auto it:sta) printf("%d ", it);
printf("\n");
}
}
signed main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
ios::sync_with_stdio(0);
cin>>n;
for (int i=1; i<=n; ++i) {
cin>>s[i];
// max_len=max(max_len, (int)s[i].length());
// sum+=(uni[++usiz]=s[i].length());
}
// pw[0]=1;
// for (int i=1; i<=max_len; ++i) pw[i]=pw[i-1]*base;
// sort(uni+1, uni+usiz+1);
// usiz=unique(uni+1, uni+usiz+1)-uni-1;
// force::solve();
task::solve();
return 0;
}