上海市青少年算法2021年10月月赛(丙组)

T1 运费计算
题目描述
快递运费的计算规则如下:
重量在 1000 克以内(包含 1000)的物品,应收取基础运费 12 元;
超出上述首重规则的物品,超重部分每 500500 克加收运费 55 元,不足 500 克的部分按 500 克计算。
给定一个正整数 aa,表示将要寄出的物品重量,请计算需要支付的运费。
输入格式
单个整数:表示寄送物品的重量 a克。
输出格式
单个整数:表示需要支付的运费。
数据范围
1≤a≤100000
样例数据
输入:
800
输出:
12
说明:
不足首重,只支付基础运费
输入:
1800
输出:
22

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
	int a;
	cin>>a;
	int cost=12;
	if(a>1000) cost+=ceil((a-1000)/500.0)*5;
	cout<<cost<<endl;
    return 0;
}

T2 阶乘的余数
题目描述
n的阶乘记为 n!,定义如下:
n!=1×2×⋯×n
给定两个正整数 n 与 m,请计算 n! 除以 m 的余数。
输入格式
第一行:两个整数表示 n 与 mm。
输出格式
单个整数:表示 n! 除以 m 的余数。
数据范围
对于 30\%30% 的数据,101≤n≤10;
对于 60\%60% 的数据,1≤n,m≤10000;
对于 100\%100% 的数据,1≤n,m≤1,000,000;
样例数据
输入:
5 1000
输出:
120
说明:
5!=120

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
	long long n,m,ans=1;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		ans=(ans*i)%m;
	cout<<ans;
    return 0;
}

T3 多边形的判定
题目描述
给定 n 个正整数 a1,a2,…,an,每个数字表示一条线段的长度,请问能否用这些线段,围成一个首尾相连且封闭的 n 边形?
n 条线段能组成 nn 边形的充分必要条件是:任何一条线段的长度都要严格小于剩余 n−1 条线段的长度之和。
输入格式
第一行:单个整数 n
第二行:n 个整数 a1,a2,…,an
​输出格式
如果可以组成 n 边形,输出 Yes,否则输出 No。
数据范围
1≤ai≤1,000,000,000;
对于 30% 的数据,1≤n≤100;
对于 60% 的数据,1≤n≤5,000;
对于 100% 的数据,1≤n≤100,000;
样例数据
输入:
6
1 3 5 2 4 6
输出:
Yes
输入:
3
1 1 2
输出:
No

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
int a[100005];
int main()
{
	long long n,sum=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		sum+=a[i];
	}
	for(int i=1;i<=n;i++){
		if(sum-a[i]<=a[i]){
			cout<<"No"<<endl;return 0;
		}
	}
	cout<<"Yes"<<endl;
    return 0;
}

T4 淘气合影
题目描述
有 n 个孩子,他们的编号为 1 到 n,老师将他们根据身高排成一条直线(注意身高和编号的顺序无关),打算拍一张集体照。但他们非常淘气,接下来的故事连续发生了五次:
老师将孩子们带到了正确的位置,然后离开摆弄相机;
一部分孩子乘机开小差,胡乱地插到其他孩子的位置中间;
老师按下快门,得到一张照片,发现有些孩子位子不对;
老师将所有开小差的孩子教育了一顿,被教育的孩子接下来就不会淘气,也不会乱跑了,返回第一步。
注意,每一轮的流程中,都可能有新的孩子出来捣乱。老师重复了五次,其中在第 i 张照片中,排在队伍中第 j 名的孩子编号为 ai,j。
小爱能从这五张照片里,还原出老师心目中原本正确的排位么?输入数据保证有解,而且有唯一解。
输入格式
第一行:一个整数 n;
第二行到第六行:每行有 n 个整数,构成一个 1 到 n 的排列。表示一张照片拍下的学生编号序列。
输出格式
表示原本正确的位置中,应该排在第i名的孩子编号
数据范围
对于 30% 的数据,1≤n≤12;
对于 60% 的数据,1≤n≤300;
对于 100% 的数据,1≤n≤100,000。
样例数据
输入:
6
2 3 4 5 1 6
2 1 3 4 5 6
3 1 2 4 5 6
4 1 2 3 5 6
5 1 2 3 4 6
输出:
1 2 3 4 5 6
说明:
第一次1号捣乱,第二次2号捣乱,以此类推,6号没有捣乱。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n;//人数
int pos[100005][6];//n人每次的站位
int a[100005];//n人的编号
//判断x是否在y的左侧
//统计x站在y左侧的次数3次以上 x在y的左侧
bool cmp(int x,int y){
	int left=0;
	for(int i=1;i<=5;i++)
		if(pos[x][i]<pos[y][i]) left++;
	return left>=3;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) a[i]=i;
	for(int i=1,x;i<=5;i++)//5次
		for(int j=1;j<=n;j++){//n人
			cin>>x;
			pos[x][i]=j;//编号x的人站的位置
		}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++) cout<<a[i]<<" ";
    return 0;
}

T5 黑白翻转棋
题目描述
有一种叫做黑白翻转棋的游戏,棋盘由 n×m 个方格组成,每个方格上放置一枚棋子,每一枚棋子一面为黑,一面为白。若翻转某枚棋子,它的颜色就会由黑变白,或者由白变黑。一开始,棋子可能是黑色的,也可能是白色的。如果把所有的格子都翻成白色,游戏就结束了。
小爱可以按照任意顺序翻转任意数量的棋子,但游戏规则规定,选择翻动某一枚棋子时,与这个棋子的方格共享边界的其它棋子也必须被同时被翻转。小爱可能在一个步骤中,同时翻转五个棋子(棋子在中间)、四个棋子(棋子在边界上)或三个棋子(当棋子在角上)。
请帮助小爱计算一下,她最少需要多少步骤才能把所有棋子都翻成白色?如果给定的初始局面是不可能结束游戏的,输出 "Impossible"。
输入格式
第一行:两个整数 n 和 m
第二行到 n+1 行:第 i+1 行有 m个整数表示初始棋盘中第 i 行棋子的颜色,1 表示黑色,0 表示白色
输出格式
如果不能将所有棋子都翻转为白面朝上的话,输出 "Impossible"。
否则输出最少翻转次数。
数据范围
对于 30% 的数据,1≤n,m≤4;
对于 60% 的数据,1≤n,m≤10;
对于 100% 的数据,1≤n,m≤20。
样例数据
输入:
3 3
0 1 0
1 1 1
0 1 0
输出:
1
说明:
翻转中间一个棋子即可

//差3个点超时了 抽时间再做更新
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int N,M,a[22][22],b[22][22];
void cop_btoa(){//将二维数组a拷贝给二维数组b
	for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++) b[i][j]=a[i][j];
}
int main()
{
	scanf("%d%d",&N,&M);//读入行、列
	for(int i=1;i<=N;i++)//读入二维数组a
		for(int j=1;j<=M;j++) scanf("%d",&a[i][j]);
	int maxx=0x7fffffff;
	for(int i=0;i<(1<<M);i++){
		cop_btoa();
		int cnt=0;
		for(int j=1;j<=M;j++){//先反转第一行
			if((i>>(j-1)) & 1){//如果第j位是1
				b[1][j]^=1;//自己
				b[1][j-1]^=1;//左
				b[1][j+1]^=1;//右
				b[2][j]^=1;//下
				cnt++;//点击一下
			}
		}
		for(int ii=2;ii<=N;ii++)//反转2~N行
			for(int jj=1;jj<=M;jj++)
				if(b[ii-1][jj]){//上一个为1
					b[ii-1][jj]^=1;//上
					b[ii][jj-1]^=1;//左
					b[ii][jj]^=1;//自己
					b[ii][jj+1]^=1;//右
					b[ii+1][jj]^=1;//下
					cnt++;
				}
		//如果全部被反转为零 则更新最少反转次数
		bool ok=true;
		for(int jj=1;jj<=M;jj++)
			if(b[N][jj]) {ok=false;break;}
		if(ok) maxx=min(maxx,cnt);
	}
	if(maxx==0x7fffffff) printf("Impossible\n");
	else printf("%d\n",maxx);
    return 0;
}

Guess you like

Origin blog.csdn.net/lybc2019/article/details/121270671