Codeforces Round #636 (Div. 3)

Codeforces Round #636 (Div. 3)

A. Candies
题目大意

给定一个n,使得x + 2x + 4x + … + 2^k-1 x = n 成立,求x,且满足k > 1。

Solution

求一个系数1 + 2 + 4 + 2^k-1 能被n整除,n/系数 即为答案。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SZ = 1e5 + 7;
const int INF = 0x3f3f3f3f;
ll n;
 
int main()
{
	int T;
	scanf("%d",&T);
	while(T --)
	{
		scanf("%lld",&n);
		ll sum = 3,t = 2;
		while(n % sum != 0)
		{
			t *= 2;
			sum += t;	
		}
		printf("%lld\n",n/sum);
	}
	return 0;
}
 

B. Balanced Array

题目大意

给定一个n,构造一个长度为n的数列,n保证是一个偶数,使得前n/2个元素全为偶数,后n/2个元素全为奇数,并且每个数字都不一样,且前半段和后半段的和相同。

Solution

前半段的和必然是偶数,后半段如果为奇数个,和是奇数,不合法,所以n/2必须是偶数。
如果合法,前半段按2,4,6,… 后半段按1, 3 , 5… 这样排列,最后一个数字加上 n/2 - 1 即可。
代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SZ = 1e5 + 7;
const int INF = 0x3f3f3f3f;
int n;
int T;
 
 
int main()
{
	int i;
	cin>>T;
	while(T--)
	{
		scanf("%d",&n);
		if ((n / 2) % 2 == 1){printf("NO");}
		else
		{
			printf("YES\n");
			for(i=1;i<=n/2;i++)
			printf("%d ",2*i);
			for(i=1;i<n/2;i++)
			printf("%d ",2*i-1);
			printf("%d",2*i+(n/2-1));
		}
		printf("\n");
	}
}

C. Alternating Subsequence

题目大意

给定一段序列,要求选出一个最长序列,使得序列中必须满足异号相邻,同号不得相邻,如果有多个最长,选出和最大的,输出和。

Solution

出现异号的就选择,同号的就找较大的一个,然后继续找异号的,再把最后一个加上即可。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int SZ = 2e5 + 7;
const int INF = 0x3f3f3f3f;
int n,f,num[SZ];
ll s,sum; 

int main()
{
	int T;
	scanf("%d",&T);
	while(T --)
	{
		f = 0,sum = 0;
		scanf("%d",&n);
		for(int i = 1;i <= n;i ++)
		{
			scanf("%d",&num[i]);
			if (f == 0)
			{
				if (num[i] < 0) f = -1;
				else f = 1;
				s = num[i];
			}
			if (f == 1 && num[i] < 0)
			{
				sum += s;
				s = num[i];
				f = -1;
			}
			if (f == -1 && num[i] > 0)
			{
				sum += s;
				s = num[i];
				f = 1;
			}
			if (num[i] > s)s = num[i];
		}
		sum += s;
		printf("%lld\n",sum);
	}
	return 0;
}

D. Constant Palindrome Sum

题目描述

给定一个长度为n的序列,其中任意一个数字的范围为1 <= ai <= k,现在你可以更改其中任何的数字,使得仍满足1 <= ai <= k,且 a[i] + a[n - i + 1] = x,对于n/2对组合x必须相同,问最少修改次数。

Solution

对于每一组,只有3种选择,不改,改一个,改两个。
对于一组数,修改一次可达到的范围 : min(num[i],num[n - i + 1]) + 1 到 max(num[i],num[n - i + 1]) + k。且中间要挖去不需要修改的点。变到其他值则需要修改2次,总范围从2到2 * k。那么做差分,再求一次前缀和,即为改到当前x所需要修改的次数,选择一个最小的即为答案。

代码

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

2020.4.23

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值