2016长乐夏令营 Day8

73 篇文章 0 订阅
44 篇文章 0 订阅

T1:

把所有边从大到小排序,for一遍,

对于每个点i开一个bitset,如果扫描到一条边(i,j) 那么bitset[j][i] = bitset[i][j] = 1

如果bitset[i] & bitset[j]  > 0 那么说明i,j已经通过一个点k相连,即当前这条边就是答案

题目貌似并不考虑三点共线,也就是说貌似三点共线也算三角形(不用特判的程序都能过)

#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 = 3010;
typedef double DB; 

struct E{
	int a,b; DB len;
	bool operator < (const E &B) const {
		return len > B.len;	
	}
	E(int _a = 0,int _b = 0,DB _len = 0) {a = _a,b = _b,len = _len;}
}edgs[maxn*maxn];

int n;
DB x[maxn],y[maxn];

bitset <maxn> bi[maxn],now;

DB cal(int i,int j)
{
	DB X = x[i] - x[j];
	DB Y = y[i] - y[j];
	return sqrt(X*X + Y*Y);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
    #else
		freopen("geometry.in","r",stdin);
		freopen("geometry.out","w",stdout);
	#endif
	
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int a,b; scanf("%d%d",&a,&b);
		x[i] = a; y[i] = b;
	}
	
	int tot = 0;
	for (int i = 1; i < n; i++)
		for (int j = i+1; j <= n; j++) 
			edgs[tot++] = E(i,j,cal(i,j));
			
	sort(edgs,edgs+tot); DB T = 2.00;
	for (int i = 0; i < tot; i++) {
		now = bi[edgs[i].a] & bi[edgs[i].b];
		if (now.count() > 0) {
			printf("%.3f",edgs[i].len/T);
			return 0;
		}
		bi[edgs[i].a][edgs[i].b] = 1;
		bi[edgs[i].b][edgs[i].a] = 1;
	}
	return 0;
}

T2:

强行树上dp,

先以1为根,

f[i]: i的子树中经过轻边的最小值

pass[i]:从i向它父亲的边被经过的次数

f[i] = ∑f[son] + ∑pass[son] - Max(pass[son])

pass[i] 通过树上前缀和求出

然后考虑换根 

g[i]:以i为根的树经过轻边的最小值

g[i] = ∑f[son] + u + ∑pass[son] + pass[x] - Max(pass[son],pass[x])

u是指将i的父亲看做i的儿子后,该子树经过轻边的最小值

u = ∑f[son] + u的u - f[i] - Maxpass

那个Max的枚举以后要用寻找最大值和次大值,不要再用lm和rm....GG

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

const int maxn = 1E5 + 10;
typedef long long LL;

LL f[maxn],g[maxn],pass[maxn],lm[maxn],rm[maxn];
int n,m,L[maxn],fa[maxn][20],son[maxn];

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

void dfs1(int x,int from)
{
	for (int i = 1; i < 20; 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;
		L[to] = L[x] + 1;
		fa[to][0] = x; ++son[x];
		dfs1(to,x);
	}
}

void dfs2(int x,int from)
{
	LL Max = 0,sum = 0;
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if (to == from) continue;
		dfs2(to,x);
		Max = max(Max,pass[to]);
		sum += pass[to];
		f[x] += f[to];
	}
	f[x] += (sum - Max);
}

void dfs3(int x,int from,LL u)
{
	LL sum,ma1,ma2,pos,tot = 0; 
	sum = ma1 = ma2 = pass[x]; pos = x;
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if (to == from) continue;
		tot += f[to];
		sum += pass[to];
		if (pass[to] >= ma1) {
			ma2 = ma1; ma1 = pass[to]; pos = i;
		}
		else if (pass[to] > ma2) ma2 = pass[to];
	}
	g[x] = (tot + u + sum - ma1);
	for (int i = 0; i < v[x].size(); i++) {
		int to = v[x][i];
		if (to == from) continue;
		LL next = u + tot - f[to] + sum - pass[to];
		if (i == pos) next -= ma2;
		else next -= ma1;
		dfs3(to,x,next);
	}
}

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][j];
	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("tree.in","r",stdin);
		freopen("tree.out","w",stdout);
	#endif
	
	cin >> n >> m;
	for (int i = 1; i < n; i++) {
		int x,y; scanf("%d%d",&x,&y);
		v[x].push_back(y);
		v[y].push_back(x);
	}
	L[1] = 1; dfs1(1,0);
	for (int i = 1; i <= m; i++) {
		int x,y; scanf("%d%d",&x,&y);
		int Lca = LCA(x,y);
		++pass[x]; ++pass[y]; pass[Lca] -= 2;
	}
	
	for  (int i = 1; i <= n; i++)
		if (!son[i]) Q.push(i);
	while (!Q.empty()) {
		int k = Q.front(); Q.pop();
		int to = fa[k][0];
		pass[to] += pass[k];
		--son[to];
		if (son[to] == 0) Q.push(to);
	}
	
	dfs2(1,0);
	dfs3(1,0,0);
	LL ans = ~0U>>1;
	for (int i = 1; i <= n; i++) ans = min(ans,g[i]);
	cout << ans;
	return 0;
}

T3:

枚举出所有合法的最小单元,设有cnt个

每个方案等价于对这cnt个单元的一种分割

间隔中可以选择割或者不割

ans = 2^(cnt-1)

不贴代码了。。。(这题重要的是思路(IQ)思路(IQ)啊)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值