程序设计思维与实践 CSP-M2 补题 (3/4/数据班)

程序设计思维与实践 CSP-M2 补题 (3/4/数据班)

A - HRZ 的序列

问题分析

题意是,序列最多由三种不同的数字的构成。当由三种数字构成时,要求这三个数排序后构成等差数列;而由两种或一种数字构成时,直接成立。

可以用STL种的set,遍历序列,每个数都加入集合中,如果集合的size大于3,不成立,输出“NO”,其他情况下,用迭代器,取出每种数字,放入数组排序。三个数字的话,必须是等差数列才输出“YES”,否则输出“NO”。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
	ll a;
	int t,n;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		set<ll>s;
		while(n--){
			scanf("%lld",&a);
			s.insert(a);
		}
		int var=s.size();
		switch(var){
			case 0:{
				return -1;
				break;
			}
			case 1:{
				printf("YES\n");
				break;
			}
			case 2:{
				printf("YES\n");
				break;
			}
			case 3:{
				ll a[3];
				int i=0;
				set<ll>::iterator iter;
				for(iter=s.begin();iter!=s.end();++iter){
					a[i++]=*iter;
				}
				sort(a,a+i);
				if(a[1]-a[0]==a[2]-a[1]){
					printf("YES\n");
				}
				else{
					printf("NO\n");
				}
				break;
			}
			default:{
				printf("NO\n");
				break;
			}
		}
	}
	return 0;
} 

B - HRZ 学英语

问题分析

从首字母开始,对一个长度为26的序列进行判定。

要求每个大写字母出现0次或者1次,每一段里面,要求大写字母和“?”的数目和为26。

输出的时候,从前往后,依次输出,可以保证字典序最小。

#include<bits/stdc++.h>
using namespace std;
int main(){
	string str;
	cin>>str;
	int l=0,r=25;
	int len=str.length();
	while(r<len){
		int letter[27]={};
		int p=l;
		while(p<=r){
			if(str[p]=='?'){
				letter[26]++;
			}
			else{
				letter[str[p]-'A']++;
				if(letter[str[p]-'A']>1){
					break;
				}
			}
			p++;
		}
		p--;
		if(p==r){
			int index=0;
			int i=l;
			while(i<=r){
				if(str[i]!='?'){
					cout<<str[i];
				}
				else{
					while(letter[index]!=0){
						index++;
					}
					cout<<(char)('A'+index);
					index++;
				}
				i++;
			}
			return 0;
		}
		l++;
		r++;
	}
	cout<<"-1"<<endl;
	return 0;
}

C - 咕咕东的奇妙序列

问题分析

错解:一开始认为题目考察数列的通项公式,直接写出了以下代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void Query(ll n)
{
	ll group=0;
	while(group*(group+1)/2<n){
		group++;
	}
	group--;
	n-=(group*(group+1)/2);
	printf("%lld\n",n);
}
int main()
{
	ll n;
	ll d;
	scanf("%lld",&n);
	while(n--){
		scanf("%lld",&d);
		Query(d);
	}
	return 0;
} 

这段代码,是求某个数的索引的,但是,题目要求的“数”,指的是数字,例如...11 12 13
这些,按照上述代码求,认为是三个数,事实上题目认为这是六个数字。

正解:有多种理解方式,很多人理解为一个由数字构成的梯形,这样就比较直观了。

关键还是确定每组数的数量。

例如,某一组有{11}{12}{13},这认为是三项,每项里还有两个数。求整个数列的第n个数,容易确定属于哪一个“组”,求这一组的第i个数,再确定它属于哪一“项”。之前的代码虽然是错的,仍然对解题有贡献。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
 
void Work() {
    LL n;
    scanf( "%lld", &n );
    LL LastLen = 0, Len, Count;
    for( Len = 1; ; ++Len ) {
        Count = 9;
        for( LL i = 1; i < Len; ++i ) 
            Count = Count * 10;
        LL Sum = ( LastLen + Len + LastLen + Count * Len ) * Count / 2;
        if( n <= Sum ) break;
        n -= Sum;
        LastLen += Count * Len;
    }
    LL Left = 1, Right = Count, Mid, Ans;
    while( Left <= Right ) {
        Mid = ( Left + Right ) >> 1;
        LL Sum = ( LastLen + Len + LastLen + Mid * Len ) * Mid / 2;
        if( Sum >= n ) {
            Ans = Mid;
            Right = Mid - 1;
        } else Left = Mid + 1;
    }
    --Ans;
    n -= ( LastLen + Len + LastLen + Ans * Len ) * Ans / 2;
    ++Ans;
    for( Len = 1; ; ++Len ) {
        Count = 9;
        for( LL i = 1; i < Len; ++i ) 
            Count = Count * 10;
        LL Sum = Count * Len;
        if( Sum >= n ) break;
        n -= Sum;
    }
    LL Num = ( n + Len - 1 ) / Len;
    n = n - ( Num - 1 ) * Len;
    LL T = 1;
    for( LL i = 1; i < Len; ++i ) T = T * 10;
    Num = T + Num - 1;
    T = Len - n + 1;
    for( LL i = 1; i < T; ++i ) Num = Num / 10;
    printf( "%lld\n", Num % 10 );
    return;
}
 
int main() {
    LL Query;
    scanf( "%lld", &Query );
    for( LL i = 1; i <= Query; ++i ) Work();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/master-cn/p/12726214.html