CF411H 被遗忘的树 Havel定理 || 网络流

全场只有3个人A的题扔过来当今天的T4.Orz DWX大爷考试时A掉这道题

网络流做法是题解做法,上CF就能看到

但是我们还有其他的方法!

我们有Havel定理的某条推论,既然这是一个树,那么某个子联通块中的点数一定大于边数

然后我们就贪心地选择,用上面的东西来判断是否可选

然后没了

结果考试的时候直接对于10的部分分输出一条链就不会了

Orz 龙哥 rand出60分

结果SDOI3道题和这道神题扔过来4个小时一起做的感觉真是爽

/* ***********************************************
Author        :BPM136
Created Time  :2016/4/25 17:00:52
File Name     :DSF.cpp
************************************************ */

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<iomanip>
#include<bitset>
#include<queue>
#include<ctime>
#include<set>
#include<map>
#include<utility>
#include<vector>
#include<functional>
#include<numeric>
#include<memory>
#include<iterator>
#define LL long long
#define DB double
#define LB long double
#define UL unsigned long
#define ULL unsigned long long
#define pb push_back
#define popb pop_back
#define get(a,i) a&(1<<(i-1))
#define PAU putchar(32)
#define ENT putchar(10)
#define clr(a,b) memset(a,b,sizeof(a))
#define fo(_i,_a,_b) for(int _i=_a;_i<=_b;_i++)
#define fd(_i,_a,_b) for(int _i=_a;_i>=_b;_i--)
#define efo(_i,_a) for(int _i=last[_a];_i!=0;_i=e[_i].next)
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
#define mkd(x) freopen(#x".in","w",stdout);
#define setlargestack(x) int size=x<<20;char *p=(char*)malloc(size)+size;__asm__("movl %0, %%esp\n" :: "r"(p));
#define end system("pause")
using namespace std;
LL read()
{
         LL f=1,d=0;char s=getchar();
         while (s<48||s>57){if (s==45) f=-1;s=getchar();}
         while (s>=48&&s<=57){d=d*10+s-48;s=getchar();}
         return f*d;
}
LL readln()
{
       LL f=1,d=0;char s=getchar();
       while (s<48||s>57){if (s==45) f=-1;s=getchar();}
       while (s>=48&&s<=57){d=d*10+s-48;s=getchar();}
       while (s!=10) s=getchar();
       return f*d;
}
inline void write(LL x)
{
    if(x==0){putchar(48);return;}if(x<0)putchar(45),x=-x;
    int len=0,buf[20];while(x)buf[len++]=x%10,x/=10;
    for(int i=len-1;i>=0;i--)putchar(buf[i]+48);return;
}
inline void writeln(LL x){write(x);ENT;}

const int N = 200010;
const int M = 7;
const int MAX = 45;

int cnt[M];
int f[N][M];

//vector<int> all[MAX];
int all[MAX][N];
int tail[MAX];
int a[MAX][MAX], sz[MAX];
int n, m = -1;

int tank[M][M][N];
int Ans[N][2];

int GetNxt() {
	char s = getchar(); int d = 1;
	while(s != '?') s = getchar();
	while(s == '?') {
		s = getchar();
		if(s == '?') d ++;
	}
	return d;
}

void init() {
//	fo(i, 0, MAX-1) all[i].clear();
	fo(i, 0, MAX - 1) tail[i] = 0;
	n = read(); 
//	scanf("%d",&n);
	fo(i, 1, n) {
		int len = 0, tmp = i;
		while(tmp > 0) {
			len ++, tmp /= 10;
		}len --;
		all[len][ tail[len]++ ] = i;
		if(len + 1 > m) m = len + 1;
//		m = max(m, len + 1);
	}
	fo(i, 0, m - 1) sz[i] = tail[i];
#define DEBUG2 looksize
//	fo(i, 0, m - 1) cout<< sz[i] << ' ';cout<<endl;
//	memset(a,0,sizeof(a));
//	char s1[MAX], s2[MAX];
	fo(i, 0, n - 2) {
		int x = GetNxt(); x --;
		int y = GetNxt(); y --;
		tank[x][y][ ++ tank[x][y][0] ] = i;
		a[x][y] ++;
#define DEBUG3 looka
//		cout<<x<<' '<<y<<endl;
	}//cout<<endl;
}

int tmp[MAX], nu;
int v, e;
bool check() {
	fo(j, 1, (1 << m) - 1) {
		nu = 0;
		fo(i, 0, m - 1)
			if(j & (1 << i)) {
				tmp[nu ++] = i;
			}

		v = 0, e = 0;
		fo(i, 0, nu - 1) v += sz[tmp[i]];
		fo(i, 0, nu - 1) 
			fo(j, 0, nu - 1) {
				e += a[tmp[i]][tmp[j]];
			}
#define DEBUG1 lookhell with the edge and ver
	//	cout<< e << ' ' << v <<endl;
		if(e >= v) return 0;
	}
	return 1;
}

void PushAns(int bit1, int bit2, int u, int v) {
	if(tank[bit1][bit2][0] == 0) swap(bit1, bit2);
	int G = tank[bit1][bit2][ tank[bit1][bit2][0] -- ];
	Ans[G][0] = u, Ans[G][1] = v;
}

void work() {
	if(check() == 0) {
		puts("-1");
		return ;
	}
#define DEBUG4 breakpoint
//	cerr<<"startwork"<<endl;
	for(;1;) {
		int flag = 0;
		fo(i, 0, m - 1) {
			fo(j, 0, m - 1) {
				if(a[i][j] == 0) continue;
				if(sz[i] > 1) {
					a[i][j] --, sz[i] --;
					if(check()) {
#define DEBUG5 lookedge1
//						write(all[i].back()); PAU; writeln(all[j][0]);
						PushAns(i, j, all[i][ tail[i]-1 ], all[j][0]);
						tail[i] --, flag = 1;
						break;
					}
					sz[i] ++, a[i][j] ++;
				}
				if(sz[j] > 1) {
					a[i][j] --, sz[j] --;
					if(check()) {
#define DEBUG6 lookedge2
//						write(all[i][0]); PAU; writeln(all[j].back());
						PushAns(i, j, all[i][0], all[j][ tail[j]-1 ]);
						tail[j] --; flag = 1;
						break;
					}
					sz[j] ++, a[i][j] ++;
				}
			}
			if(flag) break;
		}
		if(!flag) break;
	}

	fo(i, 0, m - 1) 
		fo(j, 0, m - 1) 
			if(a[i][j] > 0) {
#define DEBUG7 lookedge3
//				write(all[i].back()); PAU; writeln(all[j].back());
				PushAns(i, j, all[i][ tail[i]-1 ], all[j][ tail[j]-1 ]);
			}
	fo(i, 0, n - 2) { 
		write(Ans[i][0]); PAU; writeln(Ans[i][1]);
	}
}

int main() {
	file(D);
	DB tt = clock();
	init();
	cerr << clock() - tt <<endl; DB ttt = clock();
	work();
	cerr<< clock() - ttt <<endl;
	cerr<< "Sumtime::" << clock() - tt <<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值