2016长乐夏令营 Day11

44 篇文章 0 订阅
41 篇文章 0 订阅

T1:

惨。。当场没读懂题意?

最小割就是选出权值和最小的边集,使得删去它们后图不联通

题目硬性规定要从一棵树内选出有且仅有一条边

假如说题中的图仅仅是一棵树,那么随意割掉一条边就好

现在以这棵树的视角来看

割去一条边后,处理掉联通边两端的联通块的返祖边显然最优(不然你割这条树边干嘛?)

嗯,,至于返祖边的数量,树上前缀和搞定

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;

const int maxn = 2E4 + 20;

int n,m,T,root,fa[maxn][15],L[maxn],pass[maxn],son[maxn];

vector <int> v[maxn];
queue <int> Q; 

void dfs(int x,int from)
{
	pass[x] = 0;
	for (int i = 1; i < 15; i++)
		fa[x][i] = fa[fa[x][i-1]][i-1];
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if (to == from) continue;
		fa[to][0] = x;
		L[to] = L[x] + 1;
		dfs(to,x);
		++son[x];
	}
	if (!son[x]) Q.push(x);
}

int getint() 
{
	int ret = 0;
	char ch = getchar();
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int LCA(int p,int q)
{
	if (L[p] < L[q]) swap(p,q);
	int Log; for (Log = 0; L[p] - (1<<Log) >= 1; Log++); --Log;
	for (int j = Log; j >= 0; j--)
		if (L[p] - (1<<j) >= L[q])
			p = fa[p][0];
	if (p == q) return p;
	for (int j = Log; j >= 0; j--)
		if (fa[p][j] != fa[q][j])
			p = fa[p][j],q = fa[q][j];
	return fa[p][0];
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
    #else
		freopen("cut.in","r",stdin);
		freopen("cut.out","w",stdout);
	#endif
	
	cin >> T;
	while (T--) {
		scanf("%d%d",&n,&m);
		root = n/2;
		for (int i = 1; i < n; i++) {
			int x = getint(),y = getint();
			v[x].push_back(y);
			v[y].push_back(x);
		}
		L[root] = 1; fa[root][0] = 0;
		dfs(root,0);
		m -= (n-1);
		while (m--) {
			int x = getint(),y = getint();
			int Lca = LCA(x,y);
			++pass[x]; ++pass[y];
			pass[Lca] -= 2;
		}
		while (!Q.empty()) {
			int k = Q.front(); Q.pop();
			pass[fa[k][0]] += pass[k];
			--son[fa[k][0]];
			if (!son[fa[k][0]]) Q.push(fa[k][0]); 
		}
		int ans = ~0U>>1;
		for (int i = 1; i <= n; i++) {
			if (i != root)
				ans = min(ans,pass[i] + 1);
			v[i].clear();
		} 
		printf("%d\n",ans);
	}
	return 0;
}

T2:

现场傻逼

题目的数据等于告诉你每个吸血鬼的度数(特判吸血鬼始祖)

度数不符合就直接输出-1了

至于剩下部分,,反正你每个点的每个度数都是要填的

所以度数为1的吸血鬼显然都是叶子节点

我们需要构造一条最长的链

度数为1的显然只能做端点

于是,将所有度数不为一的吸血鬼连起来

好的,一个for

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;

const int maxn = 2020;

int T,n,m,ans,a[maxn];

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
    #else
		freopen("vampire.in","r",stdin);
		freopen("vampire.out","w",stdout);
	#endif
	
	cin >> T;
	while (T--) {
		scanf("%d",&n);
		int tot; tot = ans = 0;
		for (int i = 1; i <= n; i++) scanf("%d",&a[i]),tot += a[i];
		if (tot - n + 2 != n) {
			printf("-1\n");
			continue;
		}
		for (int i = 1; i <= n; i++) if (a[i] >= 2) ++ans;
		printf("%d\n",ans+1);
	}
	return 0;
}


T3:

f[i][j][k1][k2]:当前剩下第i到第j棵树,第i棵树的左边的树倒下的方向是k1,第j棵树右边的树倒下的方向是k2,期望覆盖长度

g[i][j][k1][k2]:状态ijk1k2发生的概率(用加法原理转移即可)

总之转移的时候记得乘上概率(一开始忘了,简直傻逼)

2000*2000*2*2的话,开个这么大的double数组空间吃紧

就用类似内存池的东西存下后面状态的更新数据(详见代码吧)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<bitset>
using namespace std;

const int maxn = 2020;
const int maxm = 100100;
typedef double DB;

struct Com{
	int pos,L,R,from; DB Add,G;
	Com(int _pos = 0,int _L = 0,int _R = 0,int _from = 0,DB _Add = 0,DB _G = 0) {
		pos = _pos; L = _L; R = _R; from = _from; Add = _Add; G = _G; 
	}
}Comder[maxm];

int n,h,cur,pos[maxn],Left[maxn],Right[maxn],
	cnt,pool[maxm],tail[maxn];
DB ans,p,q,f[maxn][2][2],g[maxn][2][2]; 

void Add(int i,int j,int l,int r,DB va,DB GG)
{
	int pos = pool[cnt--];
	Comder[pos] = Com(j,l,r,tail[i],va,GG);
	tail[i] = pos;
}

void Work(int i,int j,int l,int r)
{
	int disl = pos[i] - pos[i-1];
	if (l == 1) disl -= h;
	if (disl > h) disl = h;
	DB DISL = disl; DISL *= g[j][l][r];
	if (i == j) ans += 0.5*p*(f[j][l][r] + DISL);
	else Add(i+1,j,0,r,0.5*p*(f[j][l][r] + DISL),0.5*p*g[j][l][r]);
	
	int disr = pos[j+1] - pos[j];
	if (r == 0) disr -= h;
	if (disr > h) disr = h;
	DB DISR = disr; DISR *= g[j][l][r];
	if (i == j) ans+= 0.5*q*(f[j][l][r] + DISR);
	else f[j-1][l][1] += 0.5*q*(f[j][l][r] + DISR),g[j-1][l][1] += 0.5*q*g[j][l][r];
	
	if (Right[i] <= j) {
		int	dis = pos[Right[i]-1] - pos[i] + h;
		DB DIS = dis; DIS *= g[j][l][r];
		Add(Right[i],j,1,r,0.5*q*(f[j][l][r]+DIS),0.5*q*g[j][l][r]);
	}
	else {
		int dis = pos[j] - pos[i] + disr;
		DB DIS = dis; DIS *= g[j][l][r];
		ans += 0.5*q*(f[j][l][r] + DIS);
	}
	
	if (Left[j] >= i) {
		int dis = pos[j] - pos[Left[j]+1] + h;
		DB DIS = dis; DIS *= g[j][l][r];
		f[Left[j]][l][0] += 0.5*p*(f[j][l][r] + DIS);
		g[Left[j]][l][0] += 0.5*p*g[j][l][r];
	}
	else {
		int dis = pos[j] - pos[i] + disl;
		DB DIS = dis; DIS *= g[j][l][r];
		ans += 0.5*p*(f[j][l][r] + DIS);
	}
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
		//freopen("test.txt","w",stdout);
    #else
		freopen("tree.in","r",stdin);
		freopen("tree.out","w",stdout);
	#endif
	
	cin >> n >> h; scanf("%lf",&p); q = 1.00 - p;
	for (int i = 1; i <= n; i++) scanf("%d",&pos[i]);
	sort(pos + 1,pos + n + 1);
	pos[0] = -1E9; pos[n+1] = 1E9;
	for (int i = 1; i <= n; i++) {
		int now = i;
		for (int j = i; j > 1; j--) {
			if (pos[j] - pos[j-1] >= h) break;
			--now;
		}
		Left[i] = now - 1; now = i;
		for (int j = i; j < n; j++) {
			if (pos[j+1] - pos[j] >= h) break;
			++now;
		}
		Right[i] = now + 1;
	}
	
	for (int i = 1; i < maxm; i++) pool[i] = i; cnt = maxm - 1;
	f[n][0][0] = 0;
	g[n][0][0] = 1;
	Work(1,n,0,0);
	for (int i = 1; i <= n; i++) {
		for (int j = tail[i]; j; j = Comder[j].from) {
			Com k = Comder[j];
			f[k.pos][k.L][k.R] += k.Add;
			g[k.pos][k.L][k.R] += k.G;
			pool[++cnt] = j;
		}
		for (int j = n; j >= i; j--)
			for (int l = 0; l < 2; l++)
				for (int r = 0; r < 2; r++)
					if (f[j][l][r] > 0)
						Work(i,j,l,r);
		for (int j = i; j <= n; j++) 
			for (int l = 0; l < 2; l++)
				for (int r = 0; r < 2; r++) {
					//printf("%d %d %d %d %lf\n",i,j,l,r,f[j][l][r]);
					f[j][l][r] = 0.00;
					g[j][l][r] = 0.00;
				}
	} 
	printf("%.3lf",ans);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值