上海市计算机学会竞赛平台2023年5月月赛

第一题 三角形的分类

题目描述

给定三个角度 a a a b b b c c c。请判断这三个角在平面上能组成什么样的三角形:
如果不能组成三角形,输出 E r r o r Error Error
如果能组成等边三角形,输出 E q u i l a t e r a l Equilateral Equilateral
如果能组成等腰直角三角形,输出 I s o s c e l e s r i g h t Isosceles right Isoscelesright
如果能组成等腰三角形,输出 I s o s c e l e s Isosceles Isosceles
如果能组成直角三角形,输出 R i g h t Right Right
如果能组成不等边三角形,输出 S c a l e n e Scalene Scalene

输入格式

第一行:第一个角的角度 a a a
第二行:第二个角的角度 b b b
第三行:第三个角的角度 c c c

输出格式

根据题目要求输出对应的文字

数据范围

1 ≤ a , b , c ≤ 180 1\leq a,b,c\leq 180 1a,b,c180

样例数据

输入:

60
60
60

输出:

Equilateral

分析:if语句嵌套就行了

代码: 100分

#include <bits/stdc++.h>
using namespace std;

int main(){
	//freopen("","r",stdin);
	//freopen("","w",stdout);
	long long a,b,c;
	cin>>a>>b>>c;
	if(a==180||b==180||c==180||a+b>=180||a+c>=180||b+c>=180||a+b+c>180){
		cout<< "Error" << endl;
		return 0;
	} 
	if(a==b&&b==c&&a==c){
		cout<< "Equilateral" << endl;
	}else if(a==90&&b==c||b==90&&a==c||c==90&&a==b){
		cout<< "Isosceles right" << endl;
	}else if(a==c||a==b||b==c){
		cout<< "Isosceles" << endl;
	}else if(a==90||b==90||c==90){
		cout<< "Right" << endl;
	}else{
		cout<< "Scalene" << endl;
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}

第二题 区间最大公约数

题目描述

给定两个正整数 L , R L,R L,R,你可以任意选择两个正整数 x , y x,y x,y且满足 L ≤ x < y ≤ R L \leq x \lt y \leq R Lx<yR,并求出 x , y x,y x,y的最大公约数。
请问在所有选法中, x , y x,y x,y最大公约数的最大值为多少?

输入格式

输入共一行,两个正整数表示 L , R L,R L,R

输出格式

输出共一个整数,表示所求答案

数据范围

对于 30 % 30\% 30%的数据, 1 ≤ L < R ≤ 100 1\leq L \lt R \leq 100 1L<R100
对于 60 % 60\% 60%的数据, 1 ≤ L < R ≤ 1 0 3 1\leq L \lt R \leq 10^3 1L<R103
对于 100 % 100\% 100%的数据, 1 ≤ L < R ≤ 5 × 1 0 5 1\leq L \lt R \leq 5\times10^5 1L<R5×105

样例数据

输入:

23 29

输出:

4

说明:

(24,28)时,取到最大值为 4

输入:

32678 65536

输出:

32768

输入:

32768 32769

输出:

1

分析1:直接暴力!!!

代码:60分

#include <bits/stdc++.h>
using namespace std;

long long l,r,ans=0;

long long gcd(long long x,long long y){//最大公约数递归,不会函数的用辗转相除法,不要用枚举公约数,那效率感人
	if(y==0){
		return x;
	}else{
		return gcd(y,x%y);
	}
}

int main(){
	//freopen("","r",stdin);
	//freopen("","w",stdout);
	cin>>l>>r;
	for(int i=l;i<r;++i){//暴力硬推
		for(int j=i+1;j<=r;++j){
			long long cnt=gcd(i,j);
			ans=max(ans,cnt);
		}
	}
	cout<< ans << endl;
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}

分析2:改变一下思路

由于暴力只能拿到60分,想更高只能采取偷袭的方法

请添加图片描述

改变一下策略,之前是枚举两个数,再求公因数,那我枚举公因数,看适合它的较大那数是否超过 R R R就行了

代码2 :100分

#include <bits/stdc++.h>
using namespace std;

long long x,y,ans=1;//定义1是因为找不到公因数的话那最大就是1

int main(){
	cin>>x>>y;
	for(int i=2;i<=y;++i) if(((x+i-1)/i+1)*i<=y) ans=i;//判断
	cout<< ans << endl;
	return 0;
}

第三题 滑雪训练

题目描述

小爱最近迷上了滑雪,某滑雪场有 n n n 条不同难度的雪道,只有学习并滑了第 i i i 条雪道,才能去参加第 i + 1 i+1 i+1 条雪道的学习与训练。
已知,第一次滑第 i i i 条雪道时,需要先进行 a i a_i ai分钟的学习,再花 b i b_i bi 分钟滑该雪道一次,才算学习完成。若之后再滑第 i i i 条雪道,则仅需 b i b_i bi 分钟即可滑一次。
小爱共有 T T T 分钟时间,请问如何安排才能使他能滑的圈数最多?

输入格式

输入第一行,两个正整数 n , T n,T n,T
接下来 n n n 行:每行两个正整数 a i , b i a_i,b_i ai,bi 表示第 i i i条雪道需要的学习时间和滑雪时间。

输出格式

输出一个正整数,表示小爱最多可以滑的圈数。

数据范围

对于 30 % 30\% 30%的数据, 1 ≤ n ≤ 10 1\leq n \leq 10 1n10
对于 60 % 60\% 60%的数据, 1 ≤ n ≤ 1 0 3 1\leq n \leq 10^3 1n103
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 1 0 5 1\leq n \leq 10^5 1n105 1 ≤ a i , b i , T ≤ 1 0 18 1 \leq a_i,b_i,T \leq 10^{18} 1ai,bi,T1018

样例数据

输入:

3 100
10 20
5 5
20 10

输出:

14

说明:

先花30分钟学习第一滑道,此时共计滑了一圈
在花10分钟学习第二滑道,此时共计滑了两圈
剩余60分钟,滑第二滑道,共计滑了14

分析 1:直接暴推!!

代码1:30分

分析2:前缀和来帮忙

在代码中,有一种算法可以 O ( 1 ) O(1) O(1)求区间和,他就是前缀和!

请添加图片描述

利用前缀和算出到第 i i i圈时要花多少时间,然后看当前圈减掉学习时间后还能滑多少圈,在打擂台求出最大,就行了

代码2:100分

#include <bits/stdc++.h>
using namespace std;

long long n,s[100010],b[100010],t,x,ans=0;

int main(){
	cin>>n>>t;
	for(int i=1;i<=n;++i) cin>>x>>b[i],s[i]=s[i-1]+x+b[i];//前缀和
	for(int i=1;i<=n;++i) if(t>=s[i]) ans=max(ans,i+(t-s[i])/b[i]);//打擂台
	cout << ans << endl;
	return 0;
}

第四题 混乱的文本

题目描述

小爱正在使用一种文本编辑器输入文字。文本编辑器的工作机制如下:
若用户键入一个 [ [ [,则光标立即跳到文本的开头;
若用户键入一个 ] ] ],则光标立即跳到文本的末尾;
若用户键入任意字母,则在光标处插入该字母,且光标停留在新插入字母的后面。
给定一个字符序列,表示小爱敲击键盘录入的符号序列,请输出最后获得的文本。

输入格式

一个字符序列:表示键入的字符序列。

输出格式

一个字符序列:表示最后获得的文本。

数据范围

n n n 表示输入字符序列的长度
30 % 30\% 30% 的数据, 1 ≤ n ≤ 1000 1\leq n \leq 1000 1n1000
60 % 60\% 60% 的数据, 1 ≤ n ≤ 20 , 000 1\leq n \leq 20,000 1n20,000
100 % 100\% 100% 的数据, 1 ≤ n ≤ 300 , 000 1\leq n \leq 300,000 1n300,000

样例数据

输入:

abc[xyz]efg

输出:

xyzabcefg

分析:先看一组样例:

xyz[hd[hk[df]hgl

那如果我把’['中的字串全取出来:

hd
hk
df

再倒序输出一下:

dfhkhd

再加上’['外的:

dfhkhdxyzhgl

和结果相比:

dfhkhdxyzhgl
dfhkhdxyzhgl

这不一毛一样!!!

代码:100分

#include <bits/stdc++.h>
using namespace std;

string s,s1[300010],s2;
long long ans=0; 
char op=']';

int main() {
	cin>>s;
	for(int i=0;i<s.size();++i){
		if(s[i]=='['){
			op='[';
			ans++;
		}else if(s[i]==']'){
			op=']';
		}else{
			if(op=='['){
				s1[ans]+=s[i];
			}
			if(op==']'){
				s2+=s[i];
			}
		}
	}
	for(int i=ans;i>=1;--i){
		cout<< s1[i];
	}
	cout<< s2 << endl;
    return 0;
}

第五题最大子阵和

题目描述

给定 n × n n×n n×n 个整数组成一个方阵 a i , j a_i,_j ai,j ,请找一个 k × k k×k k×k 的子方阵,使得子方阵内的数字之和达到最大,输出这个最大值。

输入格式

第一行:两个整数 n n n k k k
第二行到第 n + 1 n+1 n+1 行:每行 n n n 个整数表示 a i , j a_i,_j ai,j

输出格式

单个整数:表示最大的 k × k k×k k×k 的子方阵的数字之和。

数据范围

30 % 30\% 30% 的数据, 1 ≤ k ≤ n ≤ 30 1≤k≤n≤30 1kn30
60 % 60\% 60% 的数据, 1 ≤ k ≤ n ≤ 300 1≤k≤n≤300 1kn300
100 % 100\% 100% 的数据, 1 ≤ k ≤ n ≤ 2500 , 0 ≤ a i , j ≤ 1 , 000 , 000 1≤k≤n≤2500,0≤a_i,_j ≤1,000,000 1kn2500,0ai,j1,000,000

样例数据

输入:

3 2
1 2 3
3 1 2
0 2 4

输出:

9

说明:

右下角最大

分析1:直接暴推!!!

代码1:30分

#include <bits/stdc++.h>
using namespace std;

long long n,k,a[3010][3010],ans=0;

int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>a[i][j];
		}
	}
	for(int i=1;i<=n-k+1;i++){
		for(int j=1;j<=n-k+1;++j){
			long long cnt=0;
			for(int x=i;x<=i+k-1;++x){
				for(int y=j;y<=j+k-1;++y){
					cnt+=a[x][y];
				}
			}
			ans=max(ans,cnt);
		}
	}
	cout << ans << endl;
	return 0;
}

分析2:二维前缀和

先看一章图:

请添加图片描述

a[x][y]的面积怎么求??
答: a x , y − 1 a_x,_y-1 ax,y1+ a x + 1 , y a_x+1,_y ax+1,y- a x − 1 , y − 1 a_x-1,_y-1 ax1,y1+m
那事先处理好数组,再把这个公式稍微改一下:
a x , y − a x − k , y − a x , y − k + a x − k , y − k a_x,_y-a_x-k,_y-a_x,_y-k+a_x-k,_y-k ax,yaxk,yax,yk+axk,yk
不过要注意,当极限数据时读入会超时,可以换scanf和printf或者关同步,或快读(本来想写快读的,没想到当天一交,就对了,那就鸽了吧)

代码2:100分

#include <bits/stdc++.h>
using namespace std;

long long s[2510][2510],n,ans=0,k,t,cnt=0;

int main(){
	//freopen("","r",stdin);
	//freopen("","w",stdout);
	ios::sync_with_stdio(false);\\关同步,注意关同步后,只能用cin,cout或scanf,printf,不然会出错
	scanf("%lld %lld",&n,&k);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			scanf("%lld",&t);
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+t;
		}
	}
	for(int i=k;i<=n;++i){
		for(int j=k;j<=n;++j){
			ans=max(ans,s[i][j]-s[i-k][j]-s[i][j-k]+s[i-k][j-k]);
		}
	}
	printf("%lld\n",ans);
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lyoi20210204

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值