程序设计思维与实践 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
");
break;
}
case 2:{
printf("YES
");
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
");
}
else{
printf("NO
");
}
break;
}
default:{
printf("NO
");
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);
}
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
", Num % 10 );
return;
}
int main() {
LL Query;
scanf( "%lld", &Query );
for( LL i = 1; i <= Query; ++i ) Work();
return 0;
}