Codeforces Round 802 (Div. 2)

基本情况

A题秒了。

B题经典+4。

C题没想法(大概想了半小时)。

B. Palindromic Numbers

Problem - B - Codeforces

起步

首先很明显是高精。

然后要求加上的数字位数和给的位数相同。

答案不限制,只要回文就行。

第一思路就是口胡几个万能的回文答案。

  • 给定的数的第一位比 \(9\)

    • 显然,把每一位都覆上 \(9\) 可以完成这个情景。

    • for (int i = 0; i < a.len; i++) tb[i] = '9';
      
  • 给定的数的第一位就是 \(9\)

    • 明显要口胡一个多一位的回文数。

    • 然后一开始我就真纯口胡了。

      if (a.str()[0] == '9')
      	{
      		int bn = a.len + 1;
      		if (bn & 1)
      		{
      			for (int i = 0; i < bn >> 1; i++)
      			{
      				tb[i] = cnt++;		
      			}
      			for (int i = bn >> 1; i < bn; i++)
      			{
      				tb[i] = cnt--;
      			}
      		}
      		else
      		{
      			for (int i = 0; i < bn >> 1; i++)
      			{
      				tb[i] = cnt++;		
      			}
      			cnt--;
      			for (int i = bn >> 1; i < bn; i++)
      			{
      				tb[i] = cnt--;
      			}
      		}
      	}
      
    • 大概就是搞一个12321这类的回文串,然而这有可能是错的啊啊

改错

幸好是发现了上面那个问题。

比如 \(n = 18\)

那么我口胡的串就是 \(1234567891011...\)

你要不看看自己在说什么。。。

一位放两位了都开始。

所以为啥不找一个和 \(999\) 一样通用的呢

\(n = 3\) 来分析:

考虑 \(a\ge 900\) 时,我们发现:

  • 只有当 \(a+b-900<1000\)\(a+b\) 减去最小的 \(a\) 不能超过 \(n\) 位数)
  • \(a+b-999\ge100\)\(a+b\) 减去最大的 \(a\) 不能不到 \(n\) 位数)
  • 随便移个项就能得到 \(1099\le a+b<1900\)
  • 在这个范围里随便拎个回文数出来(比如 \(1111\))就行了。

代码

大整数类就不复制过来了,太长了。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>

using namespace std;

char tb[100010];

void solve()
{
	int n;
	memset(tb, '\0', sizeof(tb));
	Big_integer a = Big_integer();
	cin >> n >> a;
	if (a.str()[0] == '9')
		for (int i = 0 ; i < a.len + 1; i++) tb[i] = '1';
	else
		for (int i = 0; i < a.len; i++) tb[i] = '9';
	Big_integer b = Big_integer(tb);
	cout << b - a << endl;
}

int main()
{
	int _; std::cin >> _;
	while(_--) solve();
	return 0;
}

C. Helping the Nature

Problem - C - Codeforces

要用差分,待我学学。


OK周一学成归来。

思路

我们考虑我们是怎么使得整个序列的数都变成 \(0\)

  • 将序列中的所有数都变成同一个数,然后同时加或减某一个数之后才能做到。

  • 或者将序列的中间变成 \(0\),将序列的左右部分分别变成同一个数,但是这样跟原问题有啥区别吗,还变得更加复杂了,所以就果断弃掉这个思路。

考虑如何操作使得区间中的所有数都变成同一个数:

我们考虑如果对原序列做差分,那么我们最终的答案就是差分序列所有的值为 \(0\),序列中的所有的数是同一个数。

我们会发现一个很神奇的事情:我们对于一个前缀/后缀整体减一,只会对一个位置的差分值产生影响,加一或减一,那么就利用这个性质一点一点将差分数组变成 \(0\) 就可以了。

注意:这只是将整个序列都变成同一个数,还需要将所有的数都变成 \(0\),这一步不能忘记了。

代码

对于一个差分后的值 \(x\),因为每一次操作都只能加一或减一,所以也就是 \(|x|\) 次操作后能变成 \(0\)。我的代码里维护的 \(h\) 值即差分序列全部变成 \(0\) 之后,原序列中的这个数(即原序列中所有都相同的每个数)是多少。

#include<iostream>
#include<algorithm>

const int N = 2e5 + 10;

int a[N], n;
long long b, ans;

void solve()
{
	ans = 0;
	std::cin >> n;
	for (int i = 1; i <= n; i++)
	{
		std::cin >> a[i];
	}
	long long h = a[1];
	for (int i = 2; i <= n; i++)
	{
		b = a[i - 1] - a[i];
		ans += abs(b);
		if (b > 0) h -= b;
	}
	ans += abs(h);
	std::cout << ans << std::endl;
}

int main()
{
 	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _; std::cin >> _;
	while(_--) solve();
	return 0;
}

然而这是错的!

调了半天发现是 abs 的问题。

我用的 abs 没有声明 std,所以是 C 自带的,而这个 C 自带的只能处理 intlong long 就会爆掉。

C++abs ,即加上 std::abs 就过了。

#include<iostream>
#include<algorithm>

const int N = 2e5 + 10;

int a[N], n;
long long b, ans;

void solve()
{
	ans = 0;
	std::cin >> n;
	for (int i = 1; i <= n; i++)
	{
		std::cin >> a[i];
	}
	long long h = a[1];
	for (int i = 2; i <= n; i++)
	{
		b = a[i - 1] - a[i];
		ans += std::abs(b);
		if (b > 0) h -= b;
	}
	ans += std::abs(h);
	std::cout << ans << std::endl;
}

int main()
{
 	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _; std::cin >> _;
	while(_--) solve();
	return 0;
}
posted @ 2023-12-10 16:37  加固文明幻景  阅读(3)  评论(0编辑  收藏  举报