csp模测week8

题一:HRZ的序列

题意:

给出一串序列,求有没有一个数K,使得,序列中的一些数加上K,一些数减去K,一些数不变,使得整个序列所有数相等。
输入格式:
输入第一行是一个正整数 t 表示数据组数。 接下来对于每组数据,输入的第一个正整数 n 表示序列 a 的长 度,随后一行有 n 个整数,表示序列 a。
输出格式:
输出共包含 i 行,每组数据输出一行,如果存在这样的 K,输出“YES”,否则输出“NO”。(输出不包含引号)

思路:

若输入的序列中,所有数相等,必然输出YES;
若输入序列中只有两种数,必然输出YES;
若输入序列中有三种数,若max - mid == mid - min,则输出YES,反之则输出NO;
若输入序列中有超过三种数,则必然输出NO。
为了记录共有多少种数,用一个变量sum来判断;再定义一个变量数组b[3],用来记录三种数的值;再定义一个布尔型数组got[3],用来判断是否已经得到了第 i 种数。
主函数中,在输入完成后,先对序列进行排序。然后依次从第一个数开始判断:若a[i] = b[sum-1],直接判断下一个数,若 a[i] != b[sum-1]:若sum=3,即数据总数超过三种,直接退出循环输出NO;反之,将 a[i] 赋值给 b[sum],sum自加。
在遍历完序列之后,判断如果 b[2] - b[1] = b[1] - b[0] 或者got[2] = false,输出YES,反之输出NO。

代码:

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

long long a[10005];
int sum = 0;
long long b[3];
bool got[3] = { 0, 0, 0 };

int main()
{
	int t, n;
	cin >> t;
	for (int i = 0; i < t; i++) {
		bool can = 1;
		got[0] = got[1] = got[2] = 0;
		sum = 0;
		cin >> n;
		for (int j = 0; j < n; j++) {
			cin >> a[j];
		}
		sort(a, a + n);
		//cout << a[0] << " " << a[1] << " " << a[2];
		int j = 0;
		b[0] = a[0];
		sum = 1;
		j++;
		while(j < n) {
			//1.前面放进去的和我现在要放的一样
			//if (b[sum] == a[j]) {
				//啥也别干
			//}
			// 2.前面放进去的和我现在要放的不一样
			if (b[sum - 1] != a[j]) {
				//满了
				if (sum == 3) {
					can = 0;
					break;
				}
				//没满
				else {
					b[sum] = a[j];
					sum++;
				}
			}
			j++;
		}
		//cout << b[0] << " " << b[1] << " " << b[2];
		if (can == 0 || (b[2] - b[1] != b[1] - b[0]) && sum == 3) {
			cout << "NO" << endl;
		}
		else {
			cout << "YES" << endl;
		}
	}
}

题二:HRZ学英语

题意:

给出一个字符串,包含大写字母以及字符 ‘?’。
要求:从该字符串中,取出26位子串,使得该26位子串中包含26位字母,若有‘?’,可以代替任何字母,并且在更换了‘?’之后输出26位字符串,问号部分按字典序代替字母。
输入格式:
输入一行,一个符合题目描述的字符串
输出格式:
输出一行,如果存在这样的子串,输出该子串,否则输出-1。
样例输入1:

ABC??FGHIJK???OPQR?TUVWXY?

样例输出1:

ABCDEFGHIJKLMNOPQRSTUVWXYZ

样例输入2:

AABCDEFGHIJKLMNOPQRSTUVW??M

样例输出2:

-1

思路:

一个char型数组存储字符串,一个int型数组vis用来表示子串中是否已经含有某个字母,一个char型队列queue用来存放子串。
每次从字符串中取出一个字符,判断 vis[str[i]-‘A’] 是否为 0,若为 0,则把该字符放入队列中并把 vis 赋1,若为1,则从队列头开始删除,直到删掉queue.front() = str[i]。
若队列的 size 小于26,输出 -1,反之,开始输出字符串:从queue中取出一个字符,若为‘?’,从vis[0]开始判断直到找到 vis[i] = 0 的位置,输出 (char)(i+‘A’),并把 vis 置1;若不为‘?’,输出字符。

代码:

#include <iostream>
#include <queue>
#include <string>
using namespace std;

char str[1000005];
int vis[26];//vis[0]=vis[A]	vis[str[i]-'A']
queue<char> q;

int main()
{
	while (q.size()) q.pop();
	for (int i = 0; i < 26; i++)	vis[i] = 0;
	cin >> str;
	int i = 0;
	while (str[i] != '\0' && q.size() < 26) {
		q.push(str[i]);
		if (str[i] == '?') {
			i++;
			continue;
		}
		if (vis[str[i] - 'A'] == 1) {
			while (q.front() != str[i]) {
				vis[q.front() - 'A'] = 0; 
				q.pop();
			}
			q.pop();
		}
		vis[str[i] - 'A'] = 1;
		i++;
	}
	if (q.size() < 26) {
		cout << "-1" << endl;
		return 0;
	}
	while (q.size()) {
		if (q.front() == '?') {
			int i = 0;
			while (i < 26) {
				if (vis[i] == 0) {
					cout << (char)(i + 'A');
					vis[i] = 1;
					break;
				}
				i++;
			}
		}
		else {
			cout << q.front();
			//vis[q.front() - 'A'] = 1;
		}
		q.pop();
	}
}

题三:咕咕东的奇妙序列

题意:

有一个序列,第一部分包含1到1之间的数字,第二部分包含1到2之间的数字,第三部分包含1到3之间的数字,…,第i部分包含1到i之间的数字。这个序列前56项是11212312341234512345612345671234567812345678912345678910。
求:第i项数字是多少。
输入格式:
第一行一个整数 q 表示询问 q 次
接下来第 i + 1行表示第 i 个输入 k i k_i ki,表示询问第 k i k_i ki项数字
输出格式:
输出 q 行,第 i 行输出询问 k i k_i ki 的输出结果。
样例输入:

5
1 
3 
20 
38 
56

样例输出:

1
2
5
2
0

思路:

首先定义两个数组 a 和 sum,a[i]表示第 i 部分包含几个数字,sum[i] 表示前 i 部分一共包含几个数字。可以通过a[i] = a[i-1]+wei(i),sum[i] = a[i] + sum[i-1],其中wei(i)表示一个数的位数。
给出查询的 k i k_i ki 之后,先在sum数组中找到相应的位置,判断出 k i k_i ki 在第几部分,再在第 i 部分找第 j 位数字,找第 j 位数字时,首先在a数组中找到相应的位置,判断出 j 在第几个数字,再在第 t 个数字中找第 j - a[t-1] 位,即可得到答案。

代码:

#include <iostream>
#include <math.h>
using namespace std;

long long a[2900000];//a[i]表示第i项共有a[i]位
long long sum[2900000];//sum[i]表示前i项共有sum[i]位

//得到x有几位
int wei(int x) {
	int w = 0;
	while (x != 0) {
		x = x / 10;
		w++;
	}
	return w;
}

void init() {
	a[0] = 0;
	sum[0] = 0;
	for (int i = 1; i < 2900000; i++) {
		a[i] = a[i - 1] + wei(i);
		sum[i] = a[i] + sum[i - 1];
	}
	
}

//在x中找到第y位
int getP(int x, int y) {
	int w = wei(x);
	x = x / pow(10, w - y);
	x = x % 10;
	return x;
}

//找到第 i 部分 第 j 位
int getNum(int i, long long j) {//i-10 j-10
	//找到 j 在数组 a[] 中的位置
	int k = 1; 
	while (j > a[k]) {
		k++;
	}
	return getP(k, j - a[k - 1]);
}

int main() {
	init();
	int q;
	long long k;
	cin >> q;
	for (int i = 0; i < q; i++) {
		//k = i + 1;
		cin >> k;
		if (k == 1) {
			cout << "1" << endl;
		}
		else {
			int l = 1, r = 2900000, mid;
			while (r - l > 1) {
				mid = (l + r) / 2;
				if (sum[mid] > k) {
					r = mid;
				}
				if (sum[mid] < k) {
					l = mid;
				}
				if (sum[mid] == k) {
					r = mid;
					break;
				}
			}
			cout << getNum(r, k - sum[r - 1]) << endl;
		}
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值