Codeforces Round #633 (Div. 2)

Codeforces Round #633 (Div. 2)

A. Filling Diamonds

求菱形摆放填充图形的方案数。

Solution

当一个竖着摆放的菱形确定后,其他位置都被确定了,看图中共几个可以竖着填充菱形的位置。
答案即为n。

代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef unsigned long long ll;
ll n;
 
int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{	
		scanf("%lld",&n);
		printf("%lld\n",n);
	}
	return 0;
} 

B. Sorted Adjacent Differences

把给定的n个数字的序列a1,a2,…an 重新排列。
使得新序列满足 |a1 − a2|≤|a2 − a3|≤…≤|an−1 − an|

Solution

因为要让差值越大的越靠后,所以每次取当前的最大最小放在序列的最后,即先取最大作为an,最小作为an-1,然后次大an-2,次小an-3,依次下去。
特别的要考虑奇数个的情况,最后剩的一个放到a1即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int SZ = 1e5 + 10;
int num[SZ],ans[SZ]; 
int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{
		int n;
		scanf("%d",&n);
		for(int i = 1;i <= n;i ++ )
		{
			scanf("%d",&num[i]);
		}
		int temp = n;
		sort(num + 1,num + n + 1);
		for(int i = 1;i <= n/2;i ++ )
		{
			ans[temp --] = num[i];
			ans[temp --] = num[n - i + 1];
		}
		if(n % 2 == 1) ans[temp] =num[n/2 + 1];
		for(int i = 1;i <= n;i ++ )
		printf("%d ",ans[i]);
		printf("\n");
	}
	return 0;
} 

C. Powered Addition

第i秒可以给任意l到r区间里的数字(也可不选)都加上2^(i-1),问最少几次可以使得该序列非降。

Solution

每个位置只要改成大于等于前面的最大值即可,把差值做一个前缀和即可。记录每个位置需要加上的数字大小。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SZ = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n;
ll num[SZ]; 
ll sum[SZ];
int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{
		scanf("%d",&n);
		for(int i = 1;i <= n;i ++ )
		scanf("%lld",&num[i]);
		memset(sum,0,sizeof(sum));
		for(int i = 2;i <= n;i ++ )
		{
			if(sum[i - 1] > 0) sum[i] += sum[i - 1] + num[i - 1] - num[i];
			else sum[i] +=  num[i - 1] - num[i];
		} 
			ll maxn = sum[2];
			for(int i = 3;i <= n;i ++ )
			maxn = max(sum[i],maxn);
			ll temp = 1,cnt = 0,tsum = 0;
			while(tsum < maxn)
			{
				cnt ++;
				tsum += temp;
				temp *= 2;
			}
			printf("%lld\n",cnt);
	}
	return 0;
} 

D. Edge Weight Assignment

给一个n个节点 n - 1条边的图,然后给n - 1条边附上一个权值,使得任意两个叶子之间的路径的每一条边异或和为0.
求使用不同权值的最小数量和最大数量。

Solution

首先考虑最小数量

偶数个1异或起来为0,那么如果所有叶子节点两两之间都是偶数条边,那么可以把所有边都赋值为1,最小数量也就是1。

如果存在两个叶子节点之间是奇数条边,那么全填1显然不行,我们考虑一种方案,取三条边填三个数异或起来为0(例如3,2,1),剩下的边数则为偶数条,全填1即可。故最小数量为3.

判断奇数偶数条边的具体操作方法就是任取一个叶子开始染色(黑白),然后判断是否叶子既有黑又有白。

再考虑最大数量

根据样例我们可知,一个点与他的所有叶子节点的边是一样的,也就是说它的x个叶子节点都是一样的,可以等价为只有一个,不影响权值数量的使用。所以我们先把所有的等价叶子节点缩为一个,整张图就会变成多条链相交的样子。如同样例三。

再由样例提示,变成这样的链图后,所有边都可以填一个不同的值。最大数量也就是剩下的所有边数。答案也就是剩下的点数减一。

代码

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int SZ = 1e6 + 5;
struct edge
{
	int v,nxt;
}line[SZ];
int fist[SZ],in[SZ],leaf[SZ],color[SZ];
int temp,n;
inline void build(int x,int y)
{
	line[++temp] = (edge){y,fist[x]};
	fist[x] = temp;
}
 
inline void dfs(int u,int col)
{
	color[u] = col;
	for(int i = fist[u];i != -1;i = line[i].nxt)
	{
		if(color[line[i].v]) continue;
		dfs(line[i].v,3 - col);
	}
}
 
int main()
{
	int x,y;
	memset(fist,-1,sizeof(fist));
	scanf("%d",&n);
	for(int i = 1;i < n;i ++ )
	{
		scanf("%d%d",&x,&y);
		build(x,y);
		build(y,x);
		in[x] ++;
		in[y] ++; 
	} 
	for(int i = 1;i <= n;i ++ )
	{
		if(in[i] == 1)
		leaf[line[fist[i]].v] ++ ;
	}
	int minn = 1,maxn = n - 1;
	for(int i = 1;i <= n;i ++ )
	maxn -= max(0,leaf[i] - 1);
	dfs(1,1);
	int now = 0;
	for(int i = 1;i <= n;i ++ )
	{
		if(in[i] == 1)
		{
			if(color[i] == 1) now |= 1;
			else now |= 2;
		}
	}
	if(now == 3) minn = 3;
	printf("%d %d\n",minn,maxn);
	return 0;
} 

2020.4.14

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值