Codeforces Round #245 (Div. 1) ABCDE

赛前随便选了一场 CF Div 1



A. Xor-tree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Iahub is very proud of his recent discovery, propagating trees. Right now, he invented a new tree, called xor-tree. After this new revolutionary discovery, he invented a game for kids which uses xor-trees.

The game is played on a tree having n nodes, numbered from 1 to n. Each node i has an initial value initi, which is either 0 or 1. The root of the tree is node 1.

One can perform several (possibly, zero) operations on the tree during the game. The only available type of operation is to pick a node x. Right after someone has picked node x, the value of node x flips, the values of sons of x remain the same, the values of sons of sons of x flips, the values of sons of sons of sons of x remain the same and so on.

The goal of the game is to get each node i to have value goali, which can also be only 0 or 1. You need to reach the goal of the game by using minimum number of operations.

Input

The first line contains an integer n (1 ≤ n ≤ 105). Each of the next n - 1 lines contains two integers ui and vi (1 ≤ ui, vi ≤ nui ≠ vi) meaning there is an edge between nodes ui and vi.

The next line contains n integer numbers, the i-th of them corresponds to initi (initi is either 0 or 1). The following line also contains n integer numbers, the i-th number corresponds to goali (goali is either 0 or 1).

Output

In the first line output an integer number cnt, representing the minimal number of operations you perform. Each of the next cnt lines should contain an integer xi, representing that you pick a node xi.

Examples
input
10
2 1
3 1
4 2
5 1
6 2
7 5
8 6
9 8
10 5
1 0 1 1 0 1 0 1 0 1
1 0 1 0 0 1 1 1 0 1
output
2
4
7



一棵树,每个点上可以是0或者1.对某个点的一次操作可以使自己,自己孙子,自己孙子的孙子....的权值翻转,求最少翻转多少次和翻转的点编号。


dfs,贪心地尽量翻转深度小的点即可。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=100005,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
int head[maxn],a[maxn],b[maxn];
bool visit[maxn];
int num,ans;
vector<int> v;

struct Edge {
	int from, to, pre;
};
Edge edge[maxn*2];

void addedge(int from, int to) {
	edge[num] = (Edge) {from, to, head[from]};
	head[from] = num++;
	edge[num] = (Edge) {to, from, head[to]};
	head[to] = num++;
}

void dfs(int now,int s1,int s2) {
	visit[now]=1;
	int flag=0;
	if (a[now]^s2!=b[now]) ans++,flag=1,v.push_back(now);
	for (int i=head[now];i!=-1;i=edge[i].pre) {
		int to=edge[i].to;
		if (!visit[to])
			dfs(to,s2^flag,s1);
	}
}

int main() {
	int n,x,y,i,j;
	scanf("%d",&n);
	num=0;
	memset(head,-1,sizeof(head));
	for (i=1;i<n;i++) {
		scanf("%d%d",&x,&y);
		addedge(x,y);
	}
	for (i=1;i<=n;i++) scanf("%d",&a[i]);
	for (i=1;i<=n;i++) scanf("%d",&b[i]);
	mem0(visit);ans=0;
	dfs(1,0,0);
	printf("%d\n",ans);
	for (i=0;i<v.size();i++) {
		printf("%d\n",v[i]);
	}
	return 0;
}

B. Working out
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to look hot at the beach. The gym where they go is a matrix a with n lines and m columns. Let number a[i][j] represents the calories burned by performing workout at the cell of gym in the i-th line and the j-th column.

Iahub starts with workout located at line 1 and column 1. He needs to finish with workout a[n][m]. After finishing workout a[i][j], he can go to workout a[i + 1][j] or a[i][j + 1]. Similarly, Iahubina starts with workout a[n][1] and she needs to finish with workout a[1][m]. After finishing workout from cell a[i][j], she goes to either a[i][j + 1] or a[i - 1][j].

There is one additional condition for their training. They have to meet in exactly one cell of gym. At that cell, none of them will work out. They will talk about fast exponentiation (pretty odd small talk) and then both of them will move to the next workout.

If a workout was done by either Iahub or Iahubina, it counts as total gain. Please plan a workout for Iahub and Iahubina such as total gain to be as big as possible. Note, that Iahub and Iahubina can perform workouts with different speed, so the number of cells that they use to reach meet cell may differs.

Input

The first line of the input contains two integers n and m (3 ≤ n, m ≤ 1000). Each of the next n lines contains m integers: j-th number from i-th line denotes element a[i][j] (0 ≤ a[i][j] ≤ 105).

Output

The output contains a single number — the maximum total gain possible.

Examples
input
3 3
100 100 100
100 1 100
100 100 100
output
800
Note

Iahub will choose exercises a[1][1] → a[1][2] → a[2][2] → a[3][2] → a[3][3]. Iahubina will choose exercises a[3][1] → a[2][1] → a[2][2] → a[2][3] → a[1][3].




这题有点像经典题传纸条。

一个矩阵,两个人中其中一个从左上到右下,另一个左下到右上。显然两人的路径会相遇一次,相遇格子的价值不计,其余格子的价值计算一次,问两个人所走路径的权值和最大是多少。


DP。先预处理从四个角到某点的最大权值和,再枚举相遇的格子,用四个方向到这个格子的最大权值加起来更新答案。


#include <cstdio>
#include <iostream>
#include <string.h> 
#include <algorithm> 
using namespace std;
typedef long long ll;
const int maxn=1005;
ll dp[5][maxn][maxn];
ll a[maxn][maxn];

int main() {
	int n,m,i,j,k;
	scanf("%d%d",&n,&m);
	memset(dp,0,sizeof(dp));
	for (i=1;i<=n;i++) {
		for (j=1;j<=m;j++) {
			scanf("%lld",&a[i][j]);
		}
	}
	dp[1][1][1]=a[1][1];
	for (i=1;i<=n;i++) {
		for (j=1;j<=m;j++) {
			dp[1][i+1][j]=max(dp[1][i+1][j],dp[1][i][j]+a[i+1][j]);
			dp[1][i][j+1]=max(dp[1][i][j+1],dp[1][i][j]+a[i][j+1]);
		//	cout << dp[1][i][j] << endl;
		}
	}
	dp[2][1][m]=a[1][m];
	for (i=1;i<=n;i++) {
		for (j=m;j>=1;j--) {
			dp[2][i+1][j]=max(dp[2][i+1][j],dp[2][i][j]+a[i+1][j]);
			dp[2][i][j-1]=max(dp[2][i][j-1],dp[2][i][j]+a[i][j-1]);
		}
	}
	dp[3][n][1]=a[n][1];
	for (i=n;i>=1;i--) {
		for (j=1;j<=m;j++) {
			dp[3][i-1][j]=max(dp[3][i-1][j],dp[3][i][j]+a[i-1][j]);
			dp[3][i][j+1]=max(dp[3][i][j+1],dp[3][i][j]+a[i][j+1]);
		}
	}
	dp[4][n][m]=a[n][m];
	for (i=n;i>=1;i--) {
		for (j=m;j>=1;j--) {
			dp[4][i-1][j]=max(dp[4][i-1][j],dp[4][i][j]+a[i-1][j]);
			dp[4][i][j-1]=max(dp[4][i][j-1],dp[4][i][j]+a[i][j-1]);
		}
	}
	ll ans=0;
	for (i=2;i<=n-1;i++) {
		for (j=2;j<=m-1;j++) {
			ans=max(ans,dp[1][i-1][j]+dp[4][i+1][j]+dp[2][i][j+1]+dp[3][i][j-1]);
			ans=max(ans,dp[1][i][j-1]+dp[4][i][j+1]+dp[2][i-1][j]+dp[3][i+1][j]);
		}
	}
	printf("%lld\n",ans);
	return 0;
}

C. Guess the Tree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Iahub and Iahubina went to a picnic in a forest full of trees. Less than 5 minutes passed before Iahub remembered of trees from programming. Moreover, he invented a new problem and Iahubina has to solve it, otherwise Iahub won't give her the food.

Iahub asks Iahubina: can you build a rooted tree, such that

  • each internal node (a node with at least one son) has at least two sons;
  • node i has ci nodes in its subtree?

Iahubina has to guess the tree. Being a smart girl, she realized that it's possible no tree can follow Iahub's restrictions. In this way, Iahub will eat all the food. You need to help Iahubina: determine if there's at least one tree following Iahub's restrictions. The required tree must contain n nodes.

Input

The first line of the input contains integer n (1 ≤ n ≤ 24). Next line contains n positive integers: the i-th number represents ci (1 ≤ ci ≤ n).

Output

Output on the first line "YES" (without quotes) if there exist at least one tree following Iahub's restrictions, otherwise output "NO" (without quotes).

Examples
input
                
                
4
1 1 1 4
output
YES
input
                
                
5
1 1 5 2 1
output
NO




有一棵树,给定每个点及其子树的点的数量,要求构造一棵每个点要么是叶子,要么有两个或以上儿子的树。

dfs+剪枝。
两个重要剪枝:
1.儿子的数量最少有一半(这一点可以通过画图发现),先为儿子多的点配儿子,则选择方式太多,所以应该先给儿子数量少的点配儿子。
2.对于当前搜索到的节点,当每一步选择的两个节点子树数量相同时,那么选择这两个节点具有相同的效果。因为儿子数量很多,所以这一步可以有很好的剪枝效果。

#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int inf=0x3f3f3f3f;  
const ll maxn=35,llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
int a[maxn],b[maxn],son[maxn];
bool f[maxn];
int n,cnt=0;

bool dfs(int now,int size,int son) {
	if (now>n) return true;
	if (size==a[now]&&son>=2)
		if (dfs(now+1,1,0)) return true; else return false;
	int i,last=-1;
	for (i=now-1;i>=1;i--) {
		if (size+a[i]<=a[now]&&f[i]==0&&last!=a[i]) {
			f[i]=1;last=a[i];
			if (dfs(now,size+a[i],son+1)) return true;
			f[i]=0;
		}
	}
	return false;
}

int main() {
	int i,cnt=0;
	scanf("%d",&n);
	for (i=1;i<=n;i++) {
		scanf("%d",&a[i]);
		if (a[i]==1) cnt++;
	}
	sort(a+1,a+n+1);
	mem0(f);
	if (a[n]!=n||cnt<(n+1)/2) printf("NO"); else
	if (dfs(cnt+1,1,0)) printf("YES"); else printf("NO");
	return 0;
}


D. Tricky Function
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Iahub and Sorin are the best competitive programmers in their town. However, they can't both qualify to an important contest. The selection will be made with the help of a single problem. Blatnatalag, a friend of Iahub, managed to get hold of the problem before the contest. Because he wants to make sure Iahub will be the one qualified, he tells Iahub the following task.

You're given an (1-based) array a with n elements. Let's define function f(i, j) (1 ≤ i, j ≤ n) as (i - j)2 + g(i, j)2. Function g is calculated by the following pseudo-code:

int g(int i, int j) {
    int sum = 0;
    for (int k = min(i, j) + 1; k <= max(i, j); k = k + 1)
        sum = sum + a[k];
    return sum;
}

Find a value mini ≠ j  f(i, j).

Probably by now Iahub already figured out the solution to this problem. Can you?

Input

The first line of input contains a single integer n (2 ≤ n ≤ 100000). Next line contains n integers a[1]a[2], ..., a[n] ( - 104 ≤ a[i] ≤ 104).

Output

Output a single integer — the value of mini ≠ j  f(i, j).

Examples
input
4
1 0 0 -1
output
1
input
2
1 -1
output
2

给你一个数列,问(i-j)^2+(sum[i]-sum[j])^2的最小值。


把每个(i,sum[i])看做平面的一个点,转化为最近点对问题分治进行求解。


#include <cstdio>
#include <iostream>
#include <string.h>
#include <string> 
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=100005,inf=0x3f3f3f3f;  
const ll llinf=0x3f3f3f3f3f3f3f3f;   
const ld pi=acos(-1.0L);
ll a[maxn];
int tem[maxn];

struct Point{
	int x,y;
};
Point p[maxn];

bool cmp(Point a,Point b) {
	return a.x<b.x || (a.x==b.x&&a.y<b.y);
}

bool cmpy(int a,int b) {
	return p[a].y<p[b].y;
}

ll sqr(ll x) {
	return x*x;
}

ll dfs(int l,int r) {
	if (l==r) return llinf;
	if (l+1==r) return sqr(p[l].x-p[r].x)+sqr(p[l].y-p[r].y);
	int mid=(l+r)/2;
	ll d1=dfs(l,mid),d2=dfs(mid+1,r),ans;
	ans=min(d1,d2);
	int i,j,m=0;
	for (i=l;i<=r;i++) 
		if (sqr(p[i].x-p[mid].x)<=ans) tem[m++]=i;
	sort(tem,tem+m,cmpy);
	for (i=0;i<m;i++) 
		for (j=i+1;j<m&&sqr(p[tem[i]].y-p[tem[j]].y)<ans;j++)
			ans=min(ans,sqr(p[tem[i]].x-p[tem[j]].x)+sqr(p[tem[i]].y-p[tem[j]].y));
	return ans;
}

int main() {
	int n,i;
	scanf("%d",&n);
	ll sum=0;
	for (i=1;i<=n;i++) {
		scanf("%I64d",&a[i]);
		sum+=a[i];
		p[i].x=i;p[i].y=sum;
	}
//	sort(p+1,p+n+1,cmp);
	ll ans=dfs(1,n);
	printf("%I64d\n",ans);
	return 0;
}


E. Points and Segments 欧拉回路,很有趣的一道题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值