程序设计思维与实践 CSP-M2 补题 (1/2/智能班)

A - HRZ 的序列

相较于咕咕东,瑞神是个起早贪黑的好孩子,今天早上瑞神起得很早,刷B站时看到了一个序列 ,他对这个序列产生了浓厚的兴趣,他好奇是否存在一个数 ,使得一些数加上 ,一些数减去 ,一些数不变,使得整个序列中所有的数相等,其中对于序列中的每个位置上的数字,至多只能执行一次加运算或减运算或是对该位置不进行任何操作。由于瑞神只会刷B站,所以他把这个问题交给了你!

输入格式

输入第一行是一个正整数 表示数据组数。 接下来对于每组数据,输入的第一个正整数 表示序列的长度,随后一行有 个整数,表示序列 。

输出格式

输出共包含 行,每组数据输出一行。对于每组数据,如果存在这样的K,输出"YES",否则出“NO”。(输出不包含引号)

样例输入

2
5
1 2 3 4 5
5
1 2 3 4 5

样例输出

NO
NO

思路

对于每组数据,如果这组数只由1种或2种数字组成,那么K就是两者之间的差,如果由大于3种的数组成,那么一定可以不存在这样的K,而对于由3种数字组成的数,如果中位数不是最值的平均数的话,也不存在这样的K,所以关键只需要判断平均数即可。

扫描二维码关注公众号,回复: 10874685 查看本文章

代码

#include<iostream>
#include<math.h>
using namespace std;
bool pd(long long a,long long b,long long c){
//	if((a==b)||(a==c)||(b==c)) return false;
	long long ma = max(max(a,b),c);
	long long mi = min(min(a,b),c);
	long long d = ceil((ma+mi)/2);
	if((d==a)||(d==b)||(d==c)) return true;//这里是重点 
	return false;
}
int main(){
//	freopen("in1.txt","r",stdin);
	int z;
	cin>>z;
	int n;
	while(z){
		z--;
		long long a=0,b=0,c=0;
		long long tmp;
		bool v[4];
		bool ans = true;
		for(int i=0;i<4;i++){
			v[i] = 0;
		}
		cin>>n;
		if(n<=2){
			while(n){
				cin>>tmp;
				n--;
			}
			cout<<"YES"<<endl;
		}
		else{
			scanf("%lld",&a);
			v[1] = true;
			n--;
			while(n){
				n--;
				scanf("%lld",&tmp);
				if(tmp!=a){
					if(v[2]&&tmp!=b){
						if(v[3]&&tmp!=c){
							ans = false;
						}
						else if(!v[3]){
							v[3] = true;
							c = tmp;
						}
					}
					else if(!v[2]){
						v[2] = true;
						b = tmp;
					}
				}
			}
			if(!v[2]){
				cout<<"YES"<<endl;
			}
			else if(!v[3]){
				cout<<"YES"<<endl;
			}
			else if((ans&&pd(a,b,c))) cout<<"YES"<<endl;
			else cout<<"NO"<<endl;
		}
		
	}
	return 0;
}

问题

在对long long 型数据进行处理的时候,总是产生精度上的问题,所以最好不要使用double和long long之间进行相互转换,而是只使用long long 型数据进行判断。

B - HRZ 学英语

瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想,这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字符'?',特殊字符'?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮他解决这个问题,报酬是可以帮你打守望先锋。
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排在前。

输入格式

输入只有一行,一个符合题目描述的字符串。

输出格式

输出只有一行,如果存在这样的子串,请输出,否则输出-1。

样例输入1

ABC??FGHIJK???OPQR?TUVWXY?

样例输出1

ABCDEFGHIJKLMNOPQRSTUVWXYZ

样例输入2

AABCDEFGHIJKLMNOPQRSTUVW??M

样例输出2

-1

思路

从起点移动大小为26的窗口,判断内部的数据是否符合要求,如果符合要求的话,对其中的?字符进行按照字典序更换即可。

关于字典序

字典序就是按照在英文字母表中的出现顺序代表队次序。题目中的字典序是要求按照符合要求后,在替换的时候按照整体缺少的字母的字典序进行替换。

代码

#include<iostream>
using namespace std;
string s;
char c[1000000+10];
int num[26];
bool check(int l,int r) {
	for(int i=0; i<26; i++) {
		num[i] = 0;
	}
	for(int i=l; i<r; i++) {
		if(c[i]=='?') continue;
		int index = c[i] - 'A';
		num[index]++;
		if(num[index]>1) return false;
	}
	return true;
}
int main() {
//	freopen("in2.txt","r",stdin);
	cin>>s;
	bool ans = false;
//	cout<<s<<endl;
	for(int i=0; i<s.length(); i++) {
		c[i] = s.c_str()[i];
	}
	int l = 0, r = 26;
	while(r<=s.length()) {
		if(check(l,r)) {
			ans = true;
			for(int i=l; i<r; i++) {
				if(c[i]=='?') {
					for(int j=0; j<26; j++) {
						if(num[j]==0) {
							num[j]++;
							c[i] = 'A'+j;
							break;
						}
					}
				}

			}
			break;
		} 
		else {
			l++;
			r++;
		}
	}
	if(ans)
	for(int i=l; i<r; i++) {
		cout<<c[i];
	}
	else cout<<-1;
	return 0;
}

咕咕东的奇妙序列

咕咕东 正在上可怕的复变函数,但对于稳拿A Plus的 咕咕东 来说,她早已不再听课,此时她在睡梦中突然想到了一个奇怪的无限序列:112123123412345 ......这个序列由连续正整数组成的若干部分构成,其中第一部分包含1至1之间的所有数字,第二部分包含1至2之间的所有数字,第三部分包含1至3之间的所有数字,第i部分总是包含1至i之间的所有数字。所以,这个序列的前56项会是11212312341234512345612345671234567812345678912345678910,其中第1项是1,第3项是2,第20项是5,第38项是2,第56项是0。咕咕东 现在想知道第 k 项数字是多少!但是她睡醒之后发现老师讲的东西已经听不懂了,因此她把这个任务交给了你。

输入格式

输入由多行组成。
第一行一个整数q表示有q组询问。(\(1<=q<=500\))
接下来第i+1行表示第i个输入 ,表示询问第 项数字。 (\(1<=k_i<=10^{18}\))

输出格式

输出包含q行
第i行输出对询问 的输出结果 。

样例输入

513
20
38
56

样例输出

1
2
5
2
0

思路

由于数据量庞大,直接存储这些序列显然是不现实的,所以需要先对这个序列进行观察,发现这些序列可分为n组,而每组序列的个数也可以根据其组数表达出来,所以首先我们可以判断其所在的组数,再判断其在该组的位置即可。

而对于查找其组数和位置可以采用二分的方法。

坑点

对于long long型数据的处理再次出错,可以通过中间数据暂时存储long long,而不是直接在表达式中写含有long long型的数值运算。

代码

#include<iostream>
#include<cmath>
using namespace std;//long long 后尽量不跟算式,将算式暂存起来进行计算。 
long long line(long long n){
	if(n<=9) return n;
	else if(n<=99) return (n-9)*2+9;
	else if(n<=999) return (n-99)*3+90*2+9;
	else if(n<=9999) return (n-999)*4+900*3+90*2+9;
	else if(n<=99999) return (n-9999)*5+9000*4+900*3+90*2+9;
	else if(n<=999999) return (n-99999)*6+90000*5+9000*4+900*3+90*2+9;
	else if(n<=9999999) return (n-999999)*7+line(999999);
	else if(n<=99999999) return (n-9999999)*8+line(9999999);
	else if(n<=999999999) return (n-99999999)*9+line(99999999);
//	else if(n<=9999999999) return (n-999999999)*10+900000000*9+90000000*8+9000000*7+900000*6+90000*5+9000*4+900*3+90*2+9;
//	else if(n<=99999999999) return (n-9999999999)*11+9000000000*10+900000000*9+90000000*8+9000000*7+900000*6+90000*5+9000*4+900*3+90*2+9;
}
int main(){
//	freopen("in3.txt","r",stdin);
	long long t[15];
	t[0] = 0;
	for(long long i = 1;i < 10;i++){
		long long num = ((line(pow(10,i-1))+line(pow(10,i)-1))*9*pow(10,i-1))/2;
		t[i] = t[i-1] + num;
//		cout<<t[i]<<endl;
	}
	int q;
	cin>>q;
	long long op;
	while(q){
		q--;
		scanf("%lld",&op);
		long long zu=0;
		for(long long i=1;i<10;i++){
			if(op>t[i-1]&&op<=t[i]){
				zu = i;
				break;
			}
		}
//		cout<<zu<<endl;
		long long mid = 0;
		long long left = pow(10,zu-1),right = pow(10,zu)-1;
		while(left<=right){
			mid = (left+right)/2;
			long long num = ((line(pow(10,zu-1))+line(mid))*(mid-pow(10,zu-1)+1))/2;
			long long su = t[zu-1]+num;
//			cout<<su<<endl;
			if(su>=op){
				right = mid - 1;
			}
			else {
				left = mid + 1;
			}
		}
//		cout<<left<<","<<right<<endl;
		long long num = ((line(pow(10,zu-1))+line(left))*(left-pow(10,zu-1)+1))/2;
		long long lsu = t[zu-1]+num;
		num = ((line(pow(10,zu-1))+line(right))*(right-pow(10,zu-1)+1))/2;
		long long rsu = t[zu-1]+num;
//		cout<<left<<","<<right<<","<<lsu<<","<<rsu<<endl;
//		cout<<rsu<<endl;
		long long index = op - rsu;
//		cout<<index<<endl;
		long long ans = 0;
		long long l = 1,r = left;
		long long m;
		while(l<=r){
			m = (l+r)/2;
			if(index<line(m)){
				r = m - 1;
			}
			else{
				l = m + 1;
			}
		}
//		cout<<r<<","<<l<<endl;
//		cout<<line(r)<<","<<index<<endl;
		if(index>line(r)){
			r = l;
		}
		long long tmp = line(r-1);
//		cout<<r<<","<<tmp<<","<<index<<endl;
		long long tindex = index - tmp;
//		cout<<tindex<<endl;
		long long w = floor(log(r)/log(10))+1;
		long long tt = floor(r/pow(10,w-tindex));
		ans = tt%10;
		cout<<ans<<endl;
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/mopa/p/12717617.html