CSP-M2 补题

题目一 HRZ 的序列

题目描述

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

input

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

output

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

example

input 1

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

output 1

NO
NO

做法与思路

如果k存在的话,则只有两种情况,一种是a-k=b,另一种是a-k-b-k,所以我们可以选出这组数据中的最小值和最大值,令k1=b-a,k2=(b-a)/2,然后先对k1进行检验,如果k1可行则输出YES;不可行则再对k2进行检验,可行则输出YES,不可行输出NO。

代码

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
long long a[20000];
int main(int argc, char** argv) {
	int ci;
	cin>>ci;

	for(int cci=0;cci<ci;cci++)
	{
		int judge2=0;
		int n;
		cin>>n;
		long long minn;
		long long maxx;
		cin>>a[0];
		minn=a[0];
		maxx=a[0];
		for(int i=1;i<n;i++)
		{
			cin>>a[i];
			if(a[i]>maxx)	maxx=a[i];
			if(a[i]<minn)	minn=a[i];
		}
		long long k1=maxx-minn;
		long long k2=(maxx-minn)/2;
		bool judge=0;
		for(int i=0;i<n;i++)
		{
			if((a[i]+k1!=maxx)&&(a[i]!=maxx))
			{
				judge=1;
				break;
			} 
		}
		if(judge==0)
		{
			cout<<"YES"<<endl;
			continue; 
		}
		judge=0;
		for(int i=0;i<n;i++)
		{
			if((a[i]+k2!=maxx-k2)&&(a[i]!=maxx-k2)&&(a[i]-k2!=maxx-k2))
			{
				judge=1;
				break;
			} 
		}
		if(judge==0)
		{
			cout<<"YES"<<endl;
			continue;
		}
		cout<<"NO"<<endl;
	}
	return 0;
}



题目二 HRZ学英语

题目描述

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

input

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

output

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

example

input 1

ABC??FGHIJK???OPQR?TUVWXY?

output 1

ABCDEFGHIJKLMNOPQRSTUVWXYZ

做法与思路

由于是连续区间所以第一反应就是尺取法。
尺取法的关键是判断什么情况下为“满足”。
对于该题,首先要保证区间长度为26,然后统计区间内A~Z的个数,如果存在字母个数大于1则不满足。然后把各个字母的个数加起来再加?的个数,如果总数为26,则满足条件。否则,让右端点向右移动一位。如果区间长度大于26,则让左端点向右移动一位,如果直到结束都没有满足条件则输出-1.
这里再提一下输出,因为要输出字典序最小,所以我们应该遍历这组字符串,遇到?时,按顺序遍历A~Z,如果字母的个数为0,则我们让这个字符变为该字母,同时把该字母的个数变成1即可。

代码

#include <iostream>
#include <cstring>
#include <map>
using namespace std;
map<char,int> a;
int numble;
int main(int argc, char** argv) {
	string s;
	cin>>s;
	int l=0,r=0;
	a[s[0]]++;
	while((l<=r)&&(r<s.length()))
	{
		if(r-l>25)
		{		
			a[s[l]]--;
			l++;

		}
		else if(r-l==25) 
		{
			int sum=0;
			for(char i='A';i!='[';i++)
			{
				int tem=a[i];
				if(tem>1)	break;
				sum+=tem;
			}
			sum+=a['?'];
			if(sum==26)
			{
				for(int i=l;i<=r;i++)
				{
					if(s[i]=='?')
					{
						for(char j='A';j!='[';j++)
						{
							if(a[j]==0)
							{
								cout<<j;
								a[j]=1;
								break;
							}
						}	
					}
					else cout<<s[i]; 
				}
				return 0;
			}
			else
			{
				r++;
				a[s[r]]++;
			}
		}
		else
		{
			r++;
			a[s[r]]++;
		}
	}	
	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 项数字是多少!但是她睡醒之后发现老师讲的东西已经听不懂了,因此她把这个任务交给了你。

input

输入由多行组成。
第一行一个整数q表示有q组询问。(1<=q<=500)
接下来第i+1行表示第i个输入 ,表示询问第 项数字。 (1<=ki<=1e18)

output

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

example

input 1

513
20
38
56

output 1

1
2
5
2
0

做法与思路

事实上这个题更像是一道数学寻找规律题。
数据量达到了1e18,所以穷举过去肯定是不行的,必须要缩小查找的范围。
通过观察我们发现
1
12
123

123456789
12345678910
1234567891011

1234567891011…99
1234567891011…99100

1到9时每行增长1,10到99时每行增长2,100到999时每行增长3。
这样子我们可以把数据划分成一个个梯形,先确定所要求的数据在哪个梯形中,再确定想要求的数据在该梯形的第几行中,再在该行中确定具体位置。这样就大大缩短了查找所需要的时间。
但值得注意的是,虽然梯形的数目较少,但某个梯形中的行数可能很多,如123…10000到123…99999这个梯形中整整有100000条,如果按顺序查找该数字再第几行中会超时,所以再确定行数时应该使用二分查找。

代码

#include <iostream>
#include <cmath>
#include <cstdlib> 
using namespace std;	
long long sum[10000];	
const long long maxx=pow(10,18);	
long long shang[10000];
long long xia[10000];
long long gao[10000];	

int main(int argc, char** argv) {


	long long cengshu=0;//记录层数 	
	while(sum[cengshu]<maxx)
	{
		cengshu++;
		shang[cengshu]=xia[cengshu-1]+cengshu;
		gao[cengshu]=pow(10,cengshu)-pow(10,cengshu-1);
		xia[cengshu]=shang[cengshu]+(gao[cengshu]-1)*cengshu;
		sum[cengshu]=sum[cengshu-1]+(xia[cengshu]+shang[cengshu])*gao[cengshu]/2;
		//cout<<sum[cengshu]<<endl;
	}
	int nt;
	cin>>nt;
	for(int ci=0;ci<nt;ci++)
	{
		long long t;
		cin>>t;
		int i=0;
		while(t>sum[i])
		{
			i++;//确定在哪个梯形 
		}
		long long target=t-sum[i-1];
		long long l=1;
		long long r=gao[i];
		long long mid=(r+1)/2;
		long long judge=mid*shang[i]+mid*(mid-1)/2*i;
		while(l<r)
		{
			//cout<<1<<endl; 
			mid=(r+l)/2;
			judge=mid*shang[i]+mid*(mid-1)/2*i;
			if(target>judge)
			{
				l=mid+1;
			}
			else if(target<judge)
			{
				r=mid;
			}
			else
			{
				l=mid;
				r=mid;
				break;
			}
		}//r即为所在梯形中的条数 
	//	cout<<"在第"<<i<<"个梯形的第"<<r<<"条"<<endl; 
		target-=(r-1)*shang[i]+(r-1)*(r-2)/2*i;//在该条中的位置 
//		cout<<"在该条中是第"<<target<<"个数"<<endl; 
		i=0;
		while(target>xia[i])
		{
			i++;
		}//i表示该数字所属大数字的位数,如56是10这个数字的第二个数,i则为2 
//		cout<<"所在整数的位数为"<<i<<endl;
		target=(target-xia[i-1]);
		long long shu_zi_de_ci_xu=(target-1)/i;	
//		cout<<"在位数中的位置为"<<shu_zi_de_ci_xu<<endl;
		long long shengyu=(target-1)%i; 
//		cout<<"是第"<<shengyu<<"位"<<endl; 
		long long shuzi=pow(10,i-1)+shu_zi_de_ci_xu;
//		cout<<"该数是"<<shuzi<<endl; 
		char shu[10000];
		itoa(shuzi,shu,10);
		cout<<shu[shengyu]<<endl;
	}
	return 0;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值