怕不是我再不写题解这题就该成没人做也没人会的千古谜题了......
T1:
仔细分析题面,发现相同就是广义SAM上节点相同,相似就是广义SAM上为从根到某个点路径的前缀。、
直接SAM上跑从根开始,每个点下界为1的最小流即可。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<map> 6 #include<queue> 7 #define debug cout 8 using namespace std; 9 const int maxn=5e3+1e2; 10 const int inf=0x3f3f3f3f; 11 12 int in[maxn],n,ans,sum; 13 14 namespace NetworkFlow { 15 int s[maxn<<2],t[maxn<<6],nxt[maxn<<6],f[maxn<<6],dep[maxn<<2],deg[maxn<<2],cnt=1; 16 int bak[maxn<<2],bcnt; 17 int st,ed,_s,_t; 18 inline void coredge(int from,int to,int flow) { 19 t[++cnt] = to , f[cnt] = flow , 20 nxt[cnt] = s[from] , s[from] = cnt; 21 } 22 inline void singledge(int from,int to,int flow) { 23 coredge(from,to,flow) , coredge(to,from,0); 24 } 25 inline bool bfs() { 26 memset(dep,-1,sizeof(dep)) , dep[st] = 0; 27 queue<int> q; q.push(st); 28 while( q.size() ) { 29 const int pos = q.front(); q.pop(); 30 for(int at=s[pos];at;at=nxt[at]) 31 if( f[at] && !~dep[t[at]] ) { 32 dep[t[at]] = dep[pos] + 1 , q.push(t[at]); 33 } 34 } 35 return ~dep[ed]; 36 } 37 inline int dfs(int pos,int flow) { 38 if( pos == ed ) return flow; 39 int ret = 0 , now = 0; 40 for(int at=s[pos];at;at=nxt[at]) 41 if( f[at] && dep[t[at]] > dep[pos] ) { 42 now = dfs(t[at],min(flow,f[at])) , 43 ret += now , flow -= now , 44 f[at] -= now , f[at^1] += now; 45 if( !flow ) return ret; 46 } 47 if( !ret ) dep[pos] = -1; 48 return ret; 49 } 50 inline int dinic() { 51 int ret = 0 , now = 0; 52 while( bfs() ) { 53 while( ( now = dfs(st,inf) ) ) 54 ret += now; 55 } 56 return ret; 57 } 58 inline int findflow() { 59 for(int at=s[_t];at;at=nxt[at]) 60 if( t[at] == _s ) return f[at^1]; 61 } 62 inline void backup() { 63 memcpy(bak,s,sizeof(s)) , bcnt = cnt; 64 } 65 inline void restore() { 66 memcpy(s,bak,sizeof(bak)) , cnt = bcnt; 67 } 68 } 69 70 namespace SAM { 71 map<int,int> ch[maxn<<1]; 72 int fa[maxn<<1],len[maxn<<1],root,last,cnt; 73 74 inline int NewNode(int ll) { 75 len[++cnt] = ll; 76 return cnt; 77 } 78 inline void extend(int x) { 79 int p = last; 80 int np = NewNode(len[p]+1); 81 while( p && ch[p].find(x) == ch[p].end() ) ch[p][x] = np , p = fa[p]; 82 if( !p ) fa[np] = root; 83 else { 84 int q = ch[p][x]; 85 if( len[q] == len[p] + 1 ) fa[np] = q; 86 else { 87 int nq = NewNode(len[p]+1); 88 ch[nq] = ch[q] , fa[nq] = fa[q]; 89 fa[np] = fa[q] = nq; 90 while( p && ch[p][x] == q ) ch[p][x] = nq , p = fa[p]; 91 } 92 } 93 last = np; 94 } 95 inline void Ex_extend(int* sou,int li) { 96 last = root; 97 for(int i=1;i<=li;i++) { 98 if( ch[last].find(sou[i]) != ch[last].end() ) last = ch[last][sou[i]]; 99 else extend(sou[i]); 100 } 101 } 102 } 103 104 inline void build() { 105 using SAM::ch;using SAM::cnt; 106 using namespace NetworkFlow; 107 _s = cnt * 2 + 1 , _t = _s + 1 , st = _t + 1 , ed = st + 1; 108 #define cov(x) (x+cnt) 109 for(int i=1;i<=cnt;i++) { 110 if( i != 1 ) ++deg[i] , --deg[cov(i)]; 111 for(map<int,int>::iterator it=ch[i].begin();it!=ch[i].end();it++) { 112 const int tar = it->second; 113 if( i == 1 ) singledge(_s,tar,1); 114 else singledge(cov(i),tar,1); 115 } 116 if( i != 1 ) singledge(cov(i),_t,1); 117 } 118 backup(); 119 for(int i=1;i<=_t;i++) { 120 if( !deg[i] ) continue; 121 if( deg[i] > 0 ) singledge(i,ed,deg[i]) , sum += deg[i]; 122 else singledge(st,i,-deg[i]); 123 } 124 singledge(_t,_s,inf); 125 } 126 inline int getans() { 127 using namespace NetworkFlow; 128 int d = dinic(); 129 if( d != sum ) return -1; // No solution . 130 int ret = findflow(); 131 restore(); 132 st = _t , ed = _s; 133 int dd = dinic(); 134 return ret - dd; 135 } 136 137 int main() { 138 static int m; 139 SAM::root = SAM::NewNode(0); 140 scanf("%d",&m); 141 while(m--) { 142 scanf("%d",&n); 143 for(int i=1;i<=n;i++) scanf("%d",in+i); 144 SAM::Ex_extend(in,n); 145 } 146 build(); 147 ans = getans(); 148 printf("%d\n",ans); 149 return 0; 150 }