2024年ACM 竞赛班(二:思维专题)

目录

问题 A: Deadly Laser

问题 B: Corners

题目描述

问题 C: prime check

题目描述

问题 D: PolarBear的填色游戏

题目描述

问题 E: 呆唯和连通分量

问题 F: 小z的序列

问题 G: AB Palindrome

题目描述

问题 H: Interesting Sum

题目描述

问题 I: 计算圆周率

问题 J: AB Game

题目描述


问题 A: Deadly Laser

题目描述

机器人放置在网格的左上角,网格由n行和m列组成,位于单元格(1,1)中。
在一个步骤中,它可以移动到与当前单元相邻的单元中:
(x,y)→(x,y+1);
(x,y)→(x+1,y);
(x,y)→(x,y−1);
(x,y)→(x−1、y)。
机器人不能在网格外移动。
格子(sx,sy)含有致命的激光。如果机器人进入距离激光小于或等于d的格子,它就会蒸发。两个单元(x1,y1)和(x2,y2)之间的距离定义为|x1−x2|+|y1−y2|。

打印机器人在不蒸发并且移动到网格外的情况下到达单元(n,m)所需的最小步数。如果无法到达单元格(n,m),请打印-1。

激光器既不在起始单元中,也不在结束单元中。起始单元与激光器的距离始终大于d。

这道题分两种情况

1.如果能走到,以(1,1)为起点走到(n,m),只要不走回头路,路径最短就是(n-1)+(m-1)即n+m-2。想象一个矩形,原点在左上角,终点在右下角,其中由于(sd,sy)影响部分位置不能通过。因此只要保证能沿着边缘从上边和右边走或者从左边和下边走即可。

2.不能走的话输出-1

问题 B: Corners

题目描述

给出了一个由n行和m列组成的矩阵。该矩阵的每个单元格包含0或1。
在一个操作中,您可以取一个L形图形(形如L的3格)其中至少一个单元格包含1,并将其中的所有数字替换为零。
您可以操作直至数组全变成0
找出给定矩阵可以执行的最大操作数。

直接暴力枚举过每个‘1’的“L”,统计出一个L里面最少容纳有几个’1‘,将这个L转化为’0’,剩下过‘1’的L就都能满足一个L里只有一个‘1’,答案就是‘1‘的个数减去L中最少容纳‘1’的数量加上一

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

int main()
{
	int T;
	scanf("%d",&T);
	while(T--){
		int n,m,sum=0,num,min=3;
		scanf("%d%d",&n,&m);
		char a[n+2][m+2];
		for(int i=0; i<n; i++){
			scanf("%s",&a[i]);
		}
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				num=0;
				if(a[i][j]=='1'){
					num++;sum++;
				}
				if(i-1>=0){
					if(a[i-1][j]=='1')num++;
					if(j-1>=0 && a[i][j-1]=='1'){
						num++;
						if(num<min) min=num;
						num--;
					}
					else if(j-1>=0){
						if(num<min) min=num;
					}
					if(j+1<m && a[i][j+1]=='1'){
						num++;
						if(num<min) min=num;
						num--;
					}
					else if(j+1<m){
						if(num<min) min=num;
					}
					if(a[i-1][j]=='1')num--;
				}
				if(i+1<n){
					if(a[i+1][j]=='1') num++;
					if(j-1>=0 && a[i][j-1]=='1'){
						num++;
						if(num<min) min=num;
						num--;
					}
					else if(j-1>=0){
						if(num<min) min=num;
					}
					if(j+1<m && a[i][j+1]=='1'){
						num++;
						if(num<min) min=num;
						num--;
					}
					else if(j+1<m){
						if(num<min) min=num;
					}
					if(a[i+1][j]=='1') num--;
				}
				num=0;
			}
		}
		
		if(min!=0) printf("%d\n",sum-min+1);
		else printf("%d\n",sum);
	} 
	
	return 0;
	
	
}

问题 C: prime check

题目描述

如果一个正整数大于1且不能写成两个较小的正整数的乘积,则称之为质数

素性测试是一种用于确定输入数是否为素数的算法。例如,Miller-Rabin素性测试是一种概率素性测试。这个问题正是关于素性检验的问题。

让我们将函数f(x)定义为严格大于x的最小素数。例如,f(1) = 2,f(2) = 3,f(3) = f(4) = 5。我们使用⌊�⌋

表示不超过x的最大整数 .

现在给你x,判断g(x)是否为质数.

f(x)和f(f(x))为两个相邻的质数,两个相邻的质数之间的数都是合数,1/2(f(x)+f(f(x))为两质数的平均值,因此为偶数。因为2是唯一的偶质数,四舍五入导致1/2(f(x)+f(f(x))结果为2,而其他质数都是奇数和为偶数,就不会出现上面的特殊情况所以结果都是合数。

问题 D: PolarBear的填色游戏

题目描述

PolarBear十分喜欢玩游戏,最近他发现了一个有趣的填色游戏。游戏中有�个单元格,从左到右一次排成一行。最初,所有的单元格都是白色的。如果一个白色的格子的相邻位置没有任何的红色格子,那么则认为这个格子是有效的。每一回合,玩家可以将任意有效的格子涂成红色,当游戏进行到没有有效格子时,游戏结束。玩家的分数等于他们各自涂红的单元格的数量。

PolarBear玩到入迷了,开始四处虐菜,今天他遇到了自己的手下败将dongdziz。dongdziz并不会玩这个游戏,但他坚信如果一直涂最左边的有效格子那么一定可以胜利,因此每每轮到他时,他只会将最左边的有效格子涂成红色。但PolarBear并不想赢,他只想最小化dongdziz的分数。可惜PolarBear也不想思考,他想问问你,如果PolarBear以最佳的方式最小化dongdziz的得分,dongdziz最多可以获得多少分。(dongdziz先进行第一步,然后双方轮流涂直到没有有效格子)

用D代表dongdziz填色,0代表空格,P代表PolarBear填色,则D00P0D00P0…….是最小化分数的填色方式,所以只需要看格数与5的关系即可

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int main() {
int t,n,s,k;
cin>>n;
cout<<(n-1)/5+1<<endl;
	return 0;
}

问题 E: 呆唯和连通分量

这道题其实也只需分两种情况

  1. 如果以及连通且最大的连通环量<=n满足要求不需要移动。
  2. 2.如果不满足要求,只需要移动一位把最大的连通环拆成两个就行,因为一个大于n其他环必然小于n,均满足要求。

我是模拟了链表的方式,来记录环连通的量,再用st[]保存状态优化了一下

问题 F: 小z的序列

1、2、3、4、5如果都是不同的数除了1其他的数都能找到比它小的数

如果有重复1、1、3、4、5,取出其中的1、3、4、5除了1其他数都能找到比他小的数,剩下重复的1多余

因此假设其中出现次数最多为n,第二多为a。必然可以找到a组数,满足互异性,而n-a个数多余,因此有n-a+a个数不能找到比他小的数。综上输出总数减众数个数即可。

问题 G: AB Palindrome

题目描述

给出一个由A和B构成的字符串,可以用AB替换其中的连续两个字符,并且可以替换多次,问是否能最终成为回文
字符串长度小于200000

尝试一下即可发现,因为可以用AB替换,所以除了A????B这种形式的字符串,其他字符串都可以变成回文字符串

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int main() {
	int t, n ;
string a;

	cin >> t;
	for (int i = 0; i < t; i++) {
		cin >> n;
		cin>>a;
		if(a[0]=='A'&&a[n-1]=='B')
		cout<<"No"<<endl;
		else
		cout<<"Yes"<<endl;
	}

	return 0;
}

问题 H: Interesting Sum

题目描述

给您一个包含n个整数的数组a。他是一个环,你可以任意选两个不重合的子段,使得两个子段的 最大值减去最小值的和最大
请输出可以得出最大的数

最大的和一定等于最大的两个数减去最小的两个数,因为是一个环,所以这四个值一定能被同时取到

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
    	int n;
    	scanf("%d",&n);
    	int a[n];
    	for(int i=0; i<n; i++){
    		scanf("%d",&a[i]);
		}
		sort(a,a+n);
		printf("%d\n",a[n-1]+a[n-2]-a[0]-a[1]);
		
	}
	return 0;
	
	
}

问题 I: 计算圆周率

直接输出8即可

#include <bits/stdc++.h> 
using namespace std;  
  
int main() {  
    cout << "8" << endl;
    return 0;
    
}

问题 J: AB Game

题目描述

这个游戏是由爱丽丝和鲍勃玩的。最初,有n个石头。
玩家交替轮换,做出如下所述的动作,艾丽斯先走。无法移动的玩家将失败。
轮到艾丽斯时,她必须取出a的正倍数的石头。
轮到鲍勃时,他必须取出B的正倍数的石头。
那么在总共有1个石头,2个石头,3个石头.....n个石头的n长游戏中,当两个玩家都以最佳方式玩时,Alice赢了多少次?

分情况讨论结果

1. n < a

2. n ≥ a

(1) a ≤ b

(2) a > b  ((1))(n % a) >= b

((2))(n % a) < b

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int main() {
	long long int t, n, a, b;
	cin >> t;
	for (long long int i = 0; i < t; i++) {
		cin >> n >> a >> b;
		if (n < a) {
			cout << 0 << endl;
		} else if (n >= a && a <= b) {
			cout << n - a + 1 << endl;
		} else if (n >= a && a > b && (n % a) >= b) {
			cout << n / a*b << endl;
		} else if (n >= a && a > b && (n % a) < b) {
			cout << (n / a - 1)*b + n % a + 1 << endl;
		}
	}
	return 0;
}

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值