4141:【GESP2509三级】数组清零
【题目描述】
⼩ A 有⼀个由n 个⾮负整数构成的数组 a=[a1,a2,...,an]。他会对数组a 重复进⾏以下操作,直到数组a 只包含0。在⼀次操作中,⼩ A 会依次完成以下三个步骤:
-
在数组 a 中找到最⼤的整数,记其下标为k 。如果有多个最⼤值,那么选择其中下标最⼤的。
-
从数组a 所有不为零的整数中找到最⼩的整数aj 。
-
将第⼀步找出的ak 减去aj 。
例如,数组a=[2,3,4] 需要7 次操作变成[0,0,0] :
2,3,4\]→\[2,3,2\]→\[2,1,2\]→\[2,1,1\]→\[1,1,1\]→\[1,1,0\]→\[1,0,0\]→\[0,0,0
⼩ A 想知道,对于给定的数组a ,需要多少次操作才能使得a 中的整数全部变成0 。可以证明,a 中整数必然可以在有限次操作后全部变成0 。你能帮他计算出答案吗?
【输入】
第⼀⾏,⼀个正整数n ,表⽰数组a 的长度。
第⼆⾏, n个⾮负整数a1,a2,...,an ,表⽰数组a 中的整数。
【输出】
⼀⾏,⼀个正整数,表示a 中整数全部变成0 所需要的操作次数。
【输入样例】
3
2 3 4
【输出样例】
7
【提示】
输入样例 2:
5
1 3 2 2 5
输出样例 2:
13
数据范围
对于所有测试点,保证1≤n≤100 ,1≤ai≤100。
【知识点】
1、三级及以上运行时容易超时,能提高运行效率的地方尽量去提高。
如本题运行的后半段会出现大量0,额外去满足 arr[i]!=0 可提高运行效率。
if(arr[i]!=0 && arr[i]<min0) min0=arr[i];2、只知道循环结束条件,不知循环次数,最好用while循环。有时得用while(true)死循环。
如本题循环的条件是:数组没有全为0。
while后( )中的条件不好表示,
因此写while(true),循环中再进行循环终止的判断。
【答案】
cpp
#include<bits/stdc++.h>
using namespace std;
int n, arr[105];
int main() {
cin>>n;
for(int i=0; i<n; i++) cin>>arr[i];
int num=0; //记录操作次数
while(true){
int maxid=0, min0=100; //maxid:满足条件的最大值下标, min0:最小值
for(int i=0; i<n; i++){
if(arr[i]>=arr[maxid]) maxid=i;
//运行的后半段会出现大量0,额外满足arr[i]!=0可提高运行效率。
if(arr[i]!=0 && arr[i]<min0) min0=arr[i];
}
if(arr[maxid]==0) break; //最大值为0,即数组中已全为0
arr[maxid]-=min0; //按题目要求进行操作
num++; //操作次数加1
}
cout<<num;
return 0;
}
4142:【GESP2509三级】⽇历制作
【题目描述】
⼩ A 想制作 2025 年每个⽉的⽇历。他希望你能编写⼀个程序,按照格式输出给定⽉份的⽇历。
具体来说,第⼀⾏需要输出 MON TUE WED THU FRI SAT SUN,分别表⽰星期⼀到星期⽇。接下来若⼲⾏中依次输出这个⽉所包含的⽇期,⽇期的个位需要和对应星期⼏的缩写最后⼀个字母对齐。例如,2025 年 9 ⽉ 1 ⽇是星期⼀,在输出九⽉的⽇历时,1 号的个位 1 就需要与星期⼀ MON 的最后⼀个字母 N 对齐。九⽉的⽇历输出效果如下:
MON TUE WED THU FRI SAT SUN
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
你能帮助⼩ A 完成⽇历的制作吗?
【输入】
⼀⾏,⼀个正整数m ,表⽰需要按照格式输出 2025 年m ⽉的⽇历。
【输出】
输出包含若⼲⾏,表⽰ 2025 年m ⽉的⽇历。
【输入样例】
9
【输出样例】
MON TUE WED THU FRI SAT SUN
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
【提示】
输入样例 2:
6
输出样例 2:
MON TUE WED THU FRI SAT SUN
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
数据范围:
对于所有测试点,保证1≤m≤12。
【知识点】
1、数组定义的同时,进行赋值时,不能填几个位置又空几个位置。要么都不填要么填满。
如本题:过程中要使用循环变量i来描述月份,月份的取值范围是1~12,没有0。
定义数组时最佳为:months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
其中数组的第一个位置不能为空。
2、当取值范围没有负数,但运算中有负数时,要规避负数。
如本题:题目已知25年9月第一天是星期一,通过常识也知道25年的每个月有多少天。
关键点是:要依据25年9月第一天是星期一来推出每个月的第一天是星期几。
可设变量start,来表示每个月的第一天的星期数,9月是初始为 1。
int start=1;
if(n<9){ //9月之前,往前计算天数
for(int i=8; i>=n; i--){
start-=months[i];
}
}else if(n>9){ //9月之后,往后计算天数
for(int i=9; i<n; i++){
start+=months[i];
}
}
//计算某月第一天是星期几,往前计算时会出现负数
start=(start%7+7)%7; //start%7的结果可能是负数,通过加7再对7做取余运算规避
if(start==0) start=7; //余数0是星期7
【答案】
cpp
#include<bits/stdc++.h>
using namespace std;
int n, months[13]={0,31,28,31,30,31,30,31,31,30,31,30,31}; //25年是平年,2月28天。
int main() {
cin>>n;
cout<<"MON"<<" "<<"TUE"<<" "<<"WED"<<" "<<"THU"<<" "<<"FRI"<<" "<<"SAT"<<" "<<"SUN"<<endl;
int start=1; //start某月第一天的星期数,已知信息:2025年9月1日是星期一。
if(n<9){ //9月之前,往前计算天数
for(int i=8; i>=n; i--){
start-=months[i];
}
}else if(n>9){ //9月之后,往后计算天数
for(int i=9; i<n; i++){
start+=months[i];
}
}
//计算某月第一天是星期几,往前计算时会出现负数,start%7的结果可能是负数,通过加7再对7做取余运算规避
start=(start%7+7)%7;
if(start==0) start=7; //余数0是星期7
for(int i=1; i<start; i++){ //输出每月1号之前的空格
cout<<setw(3)<<' '<<" "; //占3个字符右对齐输出
}
//从1号到月底进行输出
for(int i=1; i<=months[n]; i++){
cout<<setw(3)<<i<<" "; //占3个字符右对齐输出
if(start%7==0) cout<<endl; //每7天换行
start++;
}
return 0;
}
4046:【GESP2403三级】完全平方数
【题目描述】
小杨同学有一个包含n 个非负整数的序列A ,他想要知道其中有多少对下标组合<i,j> (1≤i,j≤n,i<j ),使得Ai+Aj是完全平方数。
如果x 是完全平方数,则存在非负整数y 使得 y×y=x。
【输入】
第一行一个非负整数n ,表示非负整数个数。
第二行包含n 个非负整数A1,A2,...,An ,表示序列A 包含的非负整数。
【输出】
输出一个非负整数,表示和是完全平方数的非负整数对数。
【输入样例】
5
1 4 3 3 5
【输出样例】
3
【提示】
对于全部数据,保证有1≤n≤1000,0≤Ai≤105 。
【知识点】
1、注意题目已知变量的取值范围
如本题:i<j2、判断一个数m是否是完全平方数:是否存在两个相同的整数相乘等于这个数
int t=int( sqrt(m) ); //计算m的平方根,强转成整数
if(t*t==m) num++; //一个整数的平方根强转为整数后,的平方如果等于自身
【答案】
cpp
#include<bits/stdc++.h>
using namespace std;
int n, a[1005]={}, num=0;
int main(){
cin>>n;
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++){
for(int j=i+1; j<=n; j++){ //保证i<j
int m=a[i]+a[j]; //计算a[i]+a[j]
//判断m是否是完全平方数:存在两个相同的整数相乘等于这个数
int t=int( sqrt(m) ); //计算m的平方根,强转成整数
if(t*t==m) num++;
}
}
cout<<num;
return 0;
}
4077:【GESP2409三级】平衡序列
【题目描述】
小杨有一个包含n个正整数的序列 a,他认为一个序列是平衡的当且仅当存在一个正整数i (1≤i<n )使得序列第1个到第i 个数字的总和等于第i+1 个到第n 个数字的总和。
小杨想请你判断序列a 是否是平衡的。
【输入】
第一行包含一个正整数t ,代表测试用例组数。
接下来是t 组测试用例。对于每组测试用例,一共两行。
第一行包含一个正整数n ,代表序列长度。
第二行包含n 个正整数,代表序列a 。
【输出】
对于每组测试用例,如果序列a 是否是平衡的,输出 Yes,否则输出 No。
【输入样例】
3
3
1 2 3
4
2 3 1 4
5
1 2 3 4 5
【输出样例】
Yes
Yes
No
【提示】
对于第一组测试用例,令i=2 ,则有1+2=3 ,因此序列是平衡的;
对于第二组测试用例,令i=2 ,则有2+3=1+4 ,因此序列是平衡的;
对于第三组测试用例,不存在满足要求的i 。
对于全部数据,保证有1≤t≤100,1≤n,ai≤10000 。
【知识点】
1、当题目输出"YES"或"NO"时,可用假设法。切记,要注意输出的大小写。
如本题:第1个数~第n个数中,是否存在第i个数,使得编号1~i的和等于i+1~n的和。
可先假设这组数符合要求:bool flag=true;
当编号1~i的和的2倍 大于 编号1~n的和时,不符合要求:flag=false; 结束循环。
当编号1~i的和的2倍 等于 编号1~n的和时,符合要求:flag=true; 结束循环。
然后继续循环继续累加,如果没有符合条件的,一定会触发"编号1~i的和的2倍 大于 编号1~n的和"。2、当题目有多组数据待判断要输出多个"YES"或"NO"时,
得把每组是否符合要求,重置为true或false,
经过代码循环测试完确定是否符合后。再判断输出结果:
bool flag=true;
......
if(flag) cout<<"YES"<<endl; //切记,要注意输出的大小写。
else cout<<"YES"<<endl;
【答案】
cpp
#include<bits/stdc++.h>
using namespace std;
int t, n, arr[10005];
int main() {
cin>>t;
while(t--){
cin>>n;
int sum=0; //sum存储所有元素的和
for(int i=1; i<=n; i++){
cin>>arr[i];
sum+=arr[i];
}
int sumi=0; //sumi存储第1个到第i个数字的总和
bool flag=true; //flag表示是否平衡,true为平衡。
for(int i=1; i<=n; i++){
sumi += arr[i];
if(sumi*2 > sum){ //sumi的2倍超过总和,不可能找到解,结束循环
flag=false; //不平衡时把true改成false。
break;
}else if(sumi*2 == sum){
//平衡时依然是true,不用变。
break; //结束循环
}
//否则继续尝试
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}