CSP-M2补题 A-HRZ的序列 B-HRZ学英语 C-咕咕东的奇妙序列

A-HRZ的序列

描述

在这里插入图片描述

思路

本题其实非常简单,但考试的时候吧这道题想得太复杂导致出错。
观察题意,让某个数加k,某些数减k,如果只有两个数其实就是平均值的问题,三个数也是要求最大数与最小数的平均值等于中间的数,但数量一多,要求就更多,因为k是固定的,而且发现数的种类一旦大于三,就不可能满足题意,因为每个数只能有三种操作,要让三个不同的数通过这三种操作得到相同的数,肯定是分别采用不同的操作所以数的种类只能小于等于三,所以问题就简单了,先求出数d

实验代码

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
	int t; cin >> t;
	while (t--) {
		int n; cin >> n;
		long long* a = new long long[n];
		int b;
		for (int i = 0; i < n; i++) cin >> a[i];
		sort(a, a + n);
		long long* count = new long long[4];
		int c = 0;
		for (int i = 0; i < n; i++) {
			if (c > 3)break;
			else if (c == 0 || a[i] != count[c-1]) 
				count[c++] = a[i];
		}
		if (c > 3)cout << "NO" << endl;
		else if (c == 3) {
			if (count[0] + count[2] == 2 * count[1])cout << "YES" << endl;
			else cout << "NO" << endl;
		}
		else if (c == 1 || c == 2)cout << "YES" << endl;
	}
	return 0;
}

B-HRZ学英语

描述

在这里插入图片描述

思路

本题考试的时候属实可惜,我记错了substr函数的参数导致截取长度不对,下来改了一下参数就过了。
本题采用的是类似尺取法,只不过这里的区间长度始终是26,我们先把l与r分别置为0和25,求得区间里面每个字符的个数,如果某个字符的个数大于1,则不满足条件,如果个数为0 的字符数量不等于?的数量,也不满足条件,不满足条件,l和r同时右移,继续相同的操作,找到第一个满足条件的就停止,将?替换为个数为零的字符(小的优先)输出的即可。

实验代码

#include <iostream>
#include <cstring>
using namespace std;
int sum[28];
void add(char op) {
	if (op == 'A')sum[1]++;
	else if (op == 'B')sum[2]++;
	else if (op == 'C')sum[3]++;
	else if (op == 'D')sum[4]++;
	else if (op == 'E')sum[5]++;
	else if (op == 'F')sum[6]++;
	else if (op == 'G')sum[7]++;
	else if (op == 'H')sum[8]++;
	else if (op == 'I')sum[9]++;
	else if (op == 'J')sum[10]++;
	else if (op == 'K')sum[11]++;
	else if (op == 'L')sum[12]++;
	else if (op == 'M')sum[13]++;
	else if (op == 'N')sum[14]++;
	else if (op == 'O')sum[15]++;
	else if (op == 'P')sum[16]++;
	else if (op == 'Q')sum[17]++;
	else if (op == 'R')sum[18]++;
	else if (op == 'S')sum[19]++;
	else if (op == 'T')sum[20]++;
	else if (op == 'U')sum[21]++;
	else if (op == 'V')sum[22]++;
	else if (op == 'W')sum[23]++;
	else if (op == 'X')sum[24]++;
	else if (op == 'Y')sum[25]++;
	else if (op == 'Z')sum[26]++;
	else if (op == '?')sum[27]++;
	return;
}
void sub(char op) {
	if (op == 'A')sum[1]--;
	else if (op == 'B')sum[2]--;
	else if (op == 'C')sum[3]--;
	else if (op == 'D')sum[4]--;
	else if (op == 'E')sum[5]--;
	else if (op == 'F')sum[6]--;
	else if (op == 'G')sum[7]--;
	else if (op == 'H')sum[8]--;
	else if (op == 'I')sum[9]--;
	else if (op == 'J')sum[10]--;
	else if (op == 'K')sum[11]--;
	else if (op == 'L')sum[12]--;
	else if (op == 'M')sum[13]--;
	else if (op == 'N')sum[14]--;
	else if (op == 'O')sum[15]--;
	else if (op == 'P')sum[16]--;
	else if (op == 'Q')sum[17]--;
	else if (op == 'R')sum[18]--;
	else if (op == 'S')sum[19]--;
	else if (op == 'T')sum[20]--;
	else if (op == 'U')sum[21]--;
	else if (op == 'V')sum[22]--;
	else if (op == 'W')sum[23]--;
	else if (op == 'X')sum[24]--;
	else if (op == 'Y')sum[25]--;
	else if (op == 'Z')sum[26]--;
	else if (op == '?')sum[27]--;
	return;
}
string s; int n;
bool check() {
	int count = 0;
	for (int i = 1; i <= 26; i++) {
		if (sum[i] > 1)return false;
		if (sum[i] == 0)count++;
	}
	if (count == sum[27])return true;
	return false;
}
int main() {
	cin >> s;
	n = s.size();
	if (n < 26) {
		cout << "-1" << endl;
		return 0;
	}
	int l = 0, r = 25;
	memset(sum, 0, sizeof(sum));
	for (int i = l; i <= r; i++)
		add(s[i]);
	string ans = "0";
	while (r <= n - 1) {
		if (check() == true) {
			ans = s.substr(l, 26);
			break;
		}
		sub(s[l]); l++; r++;
		add(s[r]);
	}
	if (ans == "0")cout << "-1" << endl;
	else {
		int temp = 0;
		for (int i = 1; i <= 26; i++) {
			if (sum[i] == 0) {
				for (int j = temp; j < 26; j++) {
					if (ans[j] == '?') {
						ans[j] = 'A' + i - 1;
						break;
					}
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

C-咕咕东的奇妙序列

描述

在这里插入图片描述

思路

本题做完发现两位数占两位,三位数占三位。。。来不及更改代码了。
本题的思路是先求出每位数的最大序列长度,每位数中的最小数所占用的序列长度,然后判断所给的k值在哪个范围,知道位数之后就好办了,但由于数值过大,迭代寻找肯定会超时,所以我们先确定了位数之后,采用二分查找求出小于等于k值的最大mid,最后k减去这个mid对应的序列长度,对剩下的序列单独做就好做了,对剩下的序列同样可以采用二分法,这里我没有使用,而是采用数学方法找出剩余序列所能到达的位数,减去该位数的最小数所占用的序列长度,再对剩下做处理就很简单了。
本题有许多细节的地方需要仔细考虑,在做的过程中也出现了许多考虑不周的问题,但是后面因为编译器选择错误导致卡了很长一段时间,换了编译器就对了。

实验代码

#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;
static long long a[15];
static long long b[15];
int main() {
	long long sum = 56;
	a[0] = 0; b[0] = 0;
	a[1] = sum; b[1] = 1;
	long long a1 = 1;
	long long an = 10;
	long long n = 0;
	for (int m = 2; m <=10 ;m++) {
		a1 = an + 1 + m;
		n = pow(10, m) - pow(10, m-1);
		an = a1 + (n-1) * m; 
		sum += (a1 + an) * n / 2 + 1;
		a[m] = sum; b[m] = a1;
	}
	//for (int i = 0; i <= 10; i++)cout << a[i]<< " "<<b[i] << endl;
	int q; cin >> q;
	while (q--) {
		long long k ;
		scanf("%lld", &k);
		long long i;
		for (i = 0; i < 10; i++)
			if (a[i] > k)break;
		long long l, r;
		if (i == 1) {
			l = 1; r = 10;
		}
		else {
			l = pow(10, i - 1)+1;
			r = pow(10, i);
		}
		long long ans1 = a[i - 1], ans2 = pow(10, i - 1);
		long long temp = l;
		while (l <= r) {
			long long mid = l + r >> 1;
			a1 = b[i]; an = a1 + (mid - temp) * i;
			sum = (a1 + an) * (mid - temp + 1) / 2 + a[i - 1];
			if (mid == pow(10, i))sum++;
			//cout << l << " " << mid << " " << r << " " << sum << endl;
			if (sum > k)r = mid - 1;
			else if (sum <= k) {
				l = mid + 1;
				ans1 = sum;
				ans2 = mid;
			}
		}
		//cout << ans1 << " " << ans2 << endl;
		k -= ans1; 
		if (k == 0)cout << ans2 % 10 << endl;
		else {
			long long j;
			for (j = 2; j <= 10; j++)
				if (k < b[j] - j)break;
			//cout << k << " " << j << " " << b[j] << endl;
			if (k > b[j] - j-j) {
				k -= (b[j] - j - j);
				if (k == 1)cout << "1" << endl;
				else cout << "0" << endl;
			}
			else {
				if (j != 2)
					k -= (b[j - 1] - j - j + 2);
				long long d = j - 1;
				long long ans = k / d;
				k -= ans * d;
				ans += (pow(10, j - 2) - 1);
				if (k != 0) {
					ans++;
					for (int m = k; m < j - 1; m++)ans /= 10;
				}
				cout <<ans % 10 << endl;
			}
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值