Codeforces Round #772 (Div. 2)

本文介绍了四道编程竞赛题目,包括A题的按位或求和,B题的局部最大值修改,C题的差分排序以及D题的无限集合问题。通过位运算和动态规划等方法,分别给出了简洁的解题思路和C++代码实现。总结了竞赛经验,提醒注意竞赛环境的稳定性。
摘要由CSDN通过智能技术生成

前言

好好练dp

A. Min Or Sum

A题戳这里

水题,没有难度

题解:

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<queue>
typedef long long ll;
 
using namespace std;
const int N = 1e5 + 10;
 
int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		ll n;
		scanf("%lld", &n);
		ll sum = 0;
		for (int i = 1;i<=n;i++){
			ll a;
			scanf("%lld", &a);
			sum = (sum | a);
		}
		printf("%lld\n", sum);
	}
	return 0;
}

B. Avoid Local Maximums

B题戳这里

找到局部最大,相邻俩局部最大改变中间的值(俩局部最大的最大值)。没有相邻的改局部最大为左右相邻两个值中最大的。(水~)

题解:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
typedef long long ll;

using namespace std;
const int N = 2e5 + 10;

int a[N];
bool b[N];

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &a[i]);
			b[i] = 0;
		}
		for (int i = 2; i < n; i++)
			if (a[i - 1] < a[i] && a[i + 1] < a[i])
				b[i] = 1;
		int sum = 0;
		for (int i = 1; i <= n; i++)
		{
			if (b[i])
			{
				sum++;
				if (i + 2 <= n && b[i + 2])
				{
					a[i + 1] = max(a[i], a[i + 2]);
					b[i] = b[i + 2] = 0;
				}
				else
				{
					a[i] = max(a[i - 1], a[i + 1]);
					b[i] = 0;
				}
			}
		}
		printf("%d\n", sum);
		for (int i = 1; i <= n; i++)
			printf("%d ", a[i]);
		printf("\n");
	}
	return 0;
}

C. Differential Sorting

C题戳这里

其实不用每个相邻的三个都看,也不用找最小操作数,直接看最后三个就好。(继续水~)

题解:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
typedef long long ll;

using namespace std;
const int N = 2e5 + 10;

int a[N];

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

D. Infinite Set

D题戳这里

设f(x)=k(k为2的指数),那么f(2x+1)=k+1,f(4x)=k+2(位运算考虑)
当一个数eg. 3时(二进制11),23=110(二进制),23+1=111(二进制),4*3=1100(二进制)
由此观之,一个数进行位运算(x>>=1(结尾为“1”)或者x>>=2(结尾为“00”)后能够得到数组中出现过的其他数字,证明可以由这些数进行运算得来,而且它进行运算之后得数也能由那个数运算得来。删掉所有这样的数字就相当于删掉了所有之后运算重复的数字。
而dp0=1,dpi=dpi-1+dpi-2,之后的运算就好处理了。


#include <bits/stdc++.h>
typedef long long ll;

using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;

int a[N];
set<int> s;
int main()
{
	int n, q;
	scanf("%d %d", &n, &q);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	sort(a + 1, a + n + 1);//记得排序
	//第一部分,位运算部分(追溯到最原始的值,看是否可以由小的值运算得来,删除会重复的元素)
	for (int i = 1; i <= n; i++)
	{
		int x = a[i];
		bool flag = 0;
		while (x > 0)
		{
			if (s.count(x))
				flag = 1;
			if (x & 1)
				x >>= 1;
			else if (x & 3)
				break;
			else
				x >>= 2;
		}
		if (!flag)
			s.insert(a[i]);
	}
	//第二部分,计算每个阶段的值,方便进行dp
	vector<int> cnt(30, 0), dp(q);
	for (int x : s)
	{
		cnt[__lg(x)]++;//对数函数
	}
	int ans = 0;
	//第三部分,dp求解
	for (int i = 0; i < q; ++i)
	{
		if (i < 30)
		{
			dp[i] = cnt[i];
		}
		if (i >= 1)
		{
			dp[i] += dp[i - 1];
			if (dp[i] >= mod)
			{
				dp[i] -= mod;
			}
		}
		if (i >= 2)
		{
			dp[i] += dp[i - 2];
			if (dp[i] >= mod)
			{
				dp[i] -= mod;
			}
		}
		ans += dp[i];
		if (ans >= mod)
		{
			ans -= mod;
		}
	}
	cout << ans << endl;
	return 0;
}

总结

网不好不要打cf(哭唧唧(

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值