CF611H New Year and Forgotten Tree [* easy]
给定 (n) 个节点的树,我们现在不知道这棵树的结构,但是我们给出了每条边连接的两个端点的十进制下的位数。
你需要构造一棵树满足此约束,(nle 2cdot 10^5)
Solution
不是吧这有 3k2 ?
首先不难观察发现所有十进制下位数相同的元素是等价的,所以对于 ?? ??
的连边我们可以直接连在 10 xx
上。
然后基于调整法,我们一定可以先将 1,10,100,1000...
联通,然后再将 (x) 一个一个的挂上去。
因为不难发现我们连接形如 ((2,50),(50,1)) 再联通此图可以调整为连接 ((2,10)) 和 ((50,1)) 使得这张图联通。
然而 (1,10...10^5) 之间的具体连边关系会影响答案,但是本质不同的树的数量只有 (6^4) 个,所以暴力枚举!
之后 check 答案,不难发现此时问题变成我们有 (k) 种操作,每次操作为给两个元素中的一个 (+1),最后需要使得所有元素的大小恰好为 (a_i)(每个元素代表十进制下位数相同的集合),那么此时就有解。
显然可以网络流建模,考虑对每种操作建一个点,向他所连接的两个集合分别连一条边,边权均为 (infty),然后 (S o opt),流量为操作次数,(i o T),流量为 (a_i)
如果满流,那么就有解,同时根据残量网络容易输出解,这张图的大小为 (6^2+8) 近似于 (50),边数也是点数的级别,非要说复杂度的话大概是 (mathcal O((log_{10} n)^{log_{10} n-2} imes (log_{10} n)^6)) 大概是 (mathcal O((log_{10} n)^{log_{10} n+4})?)
反正都能跑就对了。。
-
枚举树是写的枚举
prufer
序列,然后这玩意儿是擓的以前打 EA 的比赛时写的暴力枚举树的代码,最好还是复习一下: -
prufer 序列的生成,找到编号最小且度数为 (1) 的点,将他的父亲加入 prufer 序列结尾,删除它。
-
prufer 序列的还原,维护所有元素的出现次数,找到最小的没在序列中的元素,让它向第一个元素连边,然后删除这个元素(或者标记为 (-1))。最后将两个元素连边。
代码量虽然是 4k,但是我几乎没有调就过了,还是挺舒服的。
(Code:)
#include<bits/stdc++.h>
using namespace std ;
#define Next( i, x ) for( register int i = head[x]; i; i = e[i].next )
#define rep( i, s, t ) for( register int i = (s); i <= (t); ++ i )
#define drep( i, s, t ) for( register int i = (t); i >= (s); -- i )
#define re register
#define vi vector<int>
#define pb push_back
int gi() {
char cc = getchar() ; int cn = 0, flus = 1 ;
while( cc < '0' || cc > '9' ) { if( cc == '-' ) flus = - flus ; cc = getchar() ; }
while( cc >= '0' && cc <= '9' ) cn = cn * 10 + cc - '0', cc = getchar() ;
return cn * flus ;
}
const int inf = 1e9 + 7 ;
const int N = 2e5 + 5 ;
const int M = 100 + 5 ;
int n, m, a[10], c[10][10], bg[10], fr[10] ;
int Id(int x, int y) { return (x - 1) * m + y ; }
struct Max_Flow {
struct E {
int to, next, w ;
} e[M << 1] ;
int cnt, S, T, dep[M], head[M], cur[M] ;
void add(int x, int y, int z) {
e[++ cnt] = (E){ y, head[x], z }, head[x] = cnt,
e[++ cnt] = (E){ x, head[y], 0 }, head[y] = cnt ;
}
queue<int> q ;
bool bfs() {
memset( dep, 0, sizeof(dep) ), q.push(S), dep[S] = 1 ;
while( !q.empty() ) {
int u = q.front() ; q.pop() ;
Next( i, u ) {
int v = e[i].to ;
if( !dep[v] && e[i].w )
dep[v] = dep[u] + 1, q.push(v) ;
}
} return (dep[T] != 0) ;
}
int dfs(int x, int dist) {
if( x == T ) return dist ; int flow = 0 ;
for(re int &i = cur[x]; i; i = e[i].next ) {
int v = e[i].to ;
if( (dep[v] == dep[x] + 1) && e[i].w ) {
int di = dfs(v, min(dist, e[i].w)) ;
e[i].w -= di, e[i ^ 1].w += di,
flow += di, dist -= di ;
if( !dist ) return flow ;
}
} return flow ;
}
int dinic() {
int ans = 0 ;
while(bfs()) {
memcpy(cur, head, sizeof(head)) ;
while(int di = dfs(S, inf)) ans += di ;
} return ans ;
}
void init() { memset( head, 0, sizeof(head) ), cnt = 1 ; }
void out() {
rep( x, 1, m ) {
int u = m * m + x ;
Next( i, u ) {
int v = e[i].to ;
if( !e[i].w || (v == T) ) continue ;
rep( j, 1, x ) if(((j - 1) * m + x) == v)
while( e[i].w ) printf("%d %d
", fr[j], bg[x] ), ++ bg[x], -- e[i].w ;
rep( j, x + 1, m ) if(((x - 1) * m + j) == v)
while( e[i].w ) printf("%d %d
", fr[j], bg[x] ), ++ bg[x], -- e[i].w ;
}
}
}
} flow ;
char s[M] ;
int Num, b[M], vis[M], f[10][10] ;
void dec(int x, int y) { -- f[x][y], -- f[y][x] ; }
void check() {
rep( i, 1, m ) vis[i] = 0 ;
rep( i, 1, m ) rep( j, 1, m ) f[i][j] = c[i][j] ;
for( re int i = 1; i < m - 1; ++ i ) ++ vis[b[i]] ;
for( re int j = 1; j < m - 1; ++ j )
rep( k, 1, m ) if( vis[k] == 0 ) {
dec( k, b[j] ), -- vis[k], -- vis[b[j]] ;
break ;
}
rep( k, 1, m ) if( !vis[k] ) {
rep( j, k + 1, m ) if( vis[j] == 0 ) {
dec( j, k ) ; break ;
} break ;
}
rep( i, 1, m ) rep( j, i, m ) if( f[i][j] < 0 ) return ;
flow.init() ; int cost = 0 ;
flow.S = 0, flow.T = m * (m + 1) + 1 ;
rep( i, 1, m ) rep( j, i, m ) {
flow.add(flow.S, Id(i, j), f[i][j]), cost += f[i][j] ;
flow.add(Id(i, j), i + m * m, inf) ;
if( i != j ) flow.add(Id(i, j), j + m * m, inf) ;
}
rep( i, 1, m ) flow.add(m * m + i, flow.T, a[i]) ;
int ans = flow.dinic() ; if( ans != cost ) return ;
flow.out() ; rep( i, 1, m ) rep( j, i, m )
if( f[i][j] < c[i][j] ) printf("%d %d
", fr[i], fr[j] ) ;
exit(0) ;
}
void Dfs(int x) {
if( (x == m - 1) || (m == 1) ) return check(), void() ;
rep( i, 1, m ) b[x] = i, Dfs(x + 1) ;
}
signed main()
{
n = gi() ; int x, y ;
rep( i, 2, n ) {
scanf("%s", s + 1 ), x = strlen(s + 1) ;
scanf("%s", s + 1 ), y = strlen(s + 1) ;
if( x > y ) swap( x, y ) ; ++ c[x][y] ;
}
int len = n, z = 1 ;
while( len ) len /= 10, ++ m ;
rep( i, 1, m ) a[i] = z * 9, bg[i] = z + 1, fr[i] = z, z = z * 10 ;
a[m] = (n - z / 10) + 1 ; rep( i, 1, m ) -- a[i] ;
Dfs(1), puts("-1") ;
return 0 ;
}