Codeforces Round #833 (Div. 2)A~C题解

本文介绍了三个算法问题,涉及数学逻辑和字符串处理。A题关注如何用特定长度的木块拼成最大正方形,关键在于奇偶性判断;B题探讨优秀字符串的定义,通过限制子串长度避免暴力求解;C题讨论在数组中通过修改0获取最大贡献,利用前缀和与0的位置优化计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

A

题意:给我们最长木块的边长,木块的高永远是1,木块的长是i/2向上取整。问我们用这些木块拼成正方形的最大边长。

思路:我们通过计算可以发现连续两个可以拼成相同长度的正方形。偶数的话直接除2.奇数的话就可以除以2再加1.

#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;

void solve()
{
     long long n;
     cin >> n;
     if (n % 2 == 1)
     {
          cout << n / 2 + 1 << endl;
     }
     else
     {
          cout << n / 2 << endl;
     }
}

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

B

题意:给一个定义就是如果一个字符串内,每个字符出现的数量都小于不同的字符的个数的话,这个串就会被称为一个优秀字符串。然后给我们一个字符串,问我们有几个优秀字符子串。

思路:这个题的话有1e6的数据所以暴力肯定是不行的,我们可以想到一个字符串如果超过100个字符的话,那么它肯定不会是优秀的字符串,因为不同的字符一共就10个那么最多就是每个不同的字符出现10次,如果再出现的话就肯定是不符合要求的 。我们边遍历边求值就可以,如果记下来统一处理的话,就会出现大约 O ( n 3 ) O(n^3) O(n3)的复杂度,就肯定过不了。具体细节详见代码。

#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;

void solve()
{
	int n;
	cin >> n;
	string s;
	cin >> s;
	int ans = 0;
	for (int i = 0; i < n; i++)
	{
		string ss = "";
		unordered_map<char, int> st;
		unordered_map<char, int> mp;
		int butong = 0;
		int Max = 0;
		for (int j = i; j < n && j - i + 1 <= 100; j++)//如果串的长度超过100的话直接退出循环
		{
			if (st[s[j]] == false)
			{
				st[s[j]] = true;
				butong++;      //记不同的个数
			}
			mp[s[j]]++;
			Max = max(Max, mp[s[j]]);//找出这个子串里出现的最多的字符
			if (Max <= butong) //满足条件的话答案就加一
				ans++;
		}
	}
	cout << ans << "\n";
}

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

C

题意:给我们一个数组我们可以把一个值为0的数改为任何数。我们定义从 a 1 + a 2 + . . . + a i = 0 a_1+a_2+...+a_i = 0 a1+a2+...+ai=0的一个i为一个贡献,问我们通过无限次改变我们能得到的最大的贡献是多少。

思路:
我们可以把0作为分割,两个0之间看做一段,一个0可以影响后面的贡献,我们只把左边的0算到这一段里,右边的算到下一段里。
我们可以从后往前枚举,如果碰到一个0的话,我们就看看这一段里哪个前缀和出现次数最多,我们就加上这个前缀和出现的次数,这样的贡献肯定是最大的。
当是最左边的那一段的时候它只有右边有0,左边没有0,那么只有前缀和为0的时候才能对答案有贡献,所以我们只需要在最后加上前缀和是0的次数就可以了。
注:用unordered_map会T,map就可以,可能是建表太慢了,不如红黑树快。每查到一个0,就要重新建一次。
前缀和数组记得开long long 不然会RE

#include <iostream>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;

#define endl "\n"
const int N = 1e6 + 10;
int a[N];
long long sum[N];

void solve()
{
     int n;
     cin >> n;
     for (int i = 1; i <= n; i++)
     {
          scanf("%d", &a[i]);
          sum[i] = sum[i - 1] + a[i];
     }
     map<long long, int> mp;
     int Max = 0;
     int ans = 0;
     for (int i = n; i >= 1; i--)
     {
          mp[sum[i]]++;
          Max = max(Max, mp[sum[i]]);
          if (a[i] == 0)
          {
               ans += Max;
               mp.clear();
               Max = 0;
          }
     }
     if (mp[0])
          ans += mp[0];
     printf("%d\n", ans);
}

int main()
{
     int T;
     scanf("%d", &T);
     while (T--)
     {
          solve();
     }
     return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值