【AcWing周赛】AcWing第86场周赛

目录

<一>AcWing 4794. 健身

一、题目

1、原题链接

2、题目描述

二、解题报告

1、思路分析

2、时间复杂度

3、代码详解 

<二>AcWing 4795. 安全区域

一、题目

1、原题链接

2、题目描述

二、解题报告

1、思路分析

2、时间复杂度

3、代码详解 

<三>AcWing 4796. 删除序列

一、题目

1、原题链接

2、题目描述

二、解题报告

1、思路分析

2、时间复杂度

3、代码详解 


<一>AcWing 4794. 健身

一、题目

1、原题链接

4794. 健身 - AcWing题库

2、题目描述

李华一共要进行 n 组健身训练。

其中,第 i 组训练的时长为 ai。

李华只做三种运动:胸部(chest)运动、二头肌(biceps)运动、背部(back)运动。

而且,三种运动是循环训练的,也就是说他第一组训练是胸部运动,第二组训练是二头肌运动,第三组训练是背部运动,第四组训练是胸部运动,第五组训练是二头肌运动......以此类推直到做完第 n 组训练。

请你计算,他做哪种运动的时长最长。

输入格式

第一行包含整数 n。

第二行包含 n 个整数 a1,a2,…,an。

输出格式

共一行,如果训练时长最长的运动为:

  • 胸部运动,则输出 chest
  • 二头肌运动,则输出 biceps
  • 背部运动,则输出 back

数据保证训练时长最长的运动是唯一的。

数据范围

前 3 个测试点满足 1≤n≤7。
所有测试点满足 1≤n≤20,1≤ai≤25。

输入样例1:

2
2 8

输出样例1:

biceps

输入样例2:

3
5 1 10

输出样例2:

back

输入样例3:

7
3 3 2 7 9 6 8

输出样例3:

chest

二、解题报告

1、思路分析

根据题意进行模拟即可,对n取模3来判断当前做哪种运动,分别统计运动时长,按要求输出结果,即为所求。

2、时间复杂度

时间复杂度为O(n)

3、代码详解 

#include <iostream>
#include <algorithm>
using namespace std;
int a[25];
int num[3];
int main()
{   int n;
    cin>>n;
    for(int i=0;i<n;i++){
    	cin>>a[i];
       num[i%3]+=a[i];
    }
	int max=0;
	int index=0;
    for(int i=0;i<3;i++){
    	if(num[i]>max){
    		max=num[i];
    		index=i;
		}
	}
	if(index==0){
		cout<<"chest";
	}
	if(index==1){
		cout<<"biceps";
	}
	if(index==2){
		cout<<"back";
	}
	return 0;
}

<二>AcWing 4795. 安全区域

一、题目

1、原题链接

4795. 安全区域 - AcWing题库

2、题目描述

给定一个 n×n 的方格棋盘和 m 个国际象棋中的车。

对于一个方格,如果该方格满足以下两个条件中的至少一个,则该方格会被车攻击到:

  • 该方格内有车。
  • 至少有一个车与该方格位于同一行或同一列。

现在,我们要将 m 个车逐个放入到棋盘中,其中第 i 个车放到棋盘的第 xi 行第 yi 列的方格中。

车的编号从 1 到 m,行/列的编号从 1 到 n。

保证任意两个车不会放到同一个方格中。

对于 1≤i≤m,请你计算,将前 i 个车放入到棋盘中后,有多少个方格不会被车攻击到。

输入格式

第一行包含两个整数 n,m。

接下来 m行,其中第 i 行包含两个整数 xi,yi,表示第 i 个车放到棋盘的第 xi 行第 yi 列的方格中。

输出格式

在 1 行内输出 m 个数,其中第 i 个数表示将前 i 个车放入到棋盘中后,不会被车攻击到的方格数量。

数据范围

前 3 个测试点满足 1≤m≤3。
所有测试点满足 1≤n≤10^5,1≤m≤min(10^5,n^2),1≤xi,yi≤n。

输入样例1:

3 3
1 1
3 1
2 2

输出样例1:

4 2 0

输入样例2:

5 2
1 5
5 1

输出样例2:

16 9

输入样例3:

100000 1
300 400

输出样例3:

9999800001

二、解题报告

1、思路分析

我的思路

1)本想建立一个10^5×10^5大小的二维矩阵再进行下面操作,但是直接超范围了,若开成整型数组需要4*10^5*10^5/1024/1024MB≈40000MB,所以无法实现,于是我就建立了两个数组,分别表示x轴方向和y轴方向,并且建立两个bool类型数组来判断x,y坐标是否是车点,如果都是,则说明这个点就是车点,否则说明这一行或这一列有车。

2)直接模拟即可,我是从总体中剔除被攻击到的方格,得到的就是不会被攻击到的方格。

3)TLE,最终只过了4个数据点。

思路来源:AcWing 4795. 安全区域(AcWing杯 - 周赛) - AcWing

y总yyds

y总思路

1)直接统计有总共多少行上有车,多少列上有车,假设有r行上有车,c列上也有车,则不能被攻击到的方格个数满足(n-r)*(n-c)[将这r行和c列都移到矩阵最上方和最左方,剩下的格子总数就是(n-r)*(n-c)]。

2)每加入一个车,统计当前多少行有车,多少列有车,然后根据公式输出结果,即为所求。

2、时间复杂度

我的思路的时间复杂度为O(n^2)

y总思路的时间复杂度为O(n)

3、代码详解 

我的思路的代码

#include <iostream>
using namespace std;
long long dx[100010];
long long dy[100010];
bool isx[100010];
bool isy[100010];
long long x[100010];
long long y[100010];
long long M[100010];
int main()
{   long long n,m;
    cin>>n>>m;
    for(int i=0;i<m;i++){
    	long long ans=n*n;
		cin>>x[i]>>y[i];
    	dx[x[i]]=1;
    	dy[y[i]]=1;
    	isx[x[i]]=1;
    	isy[y[i]]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(dx[i]==1&&dy[i]==1||isx[i]==1||isy[j]==1){
				ans--;
			}
		}
	}
	M[i]=ans;
	}
	for(int i=0;i<m;i++){
		cout<<M[i]<<" ";
	}
	return 0;
}

y总思路的代码 

#include <iostream>
using namespace std;
bool r[100010],c[100010];
int main()
{   int n,m;
    cin>>n>>m;
    int x,y;
    int rnum=0,cnum=0;
    for(int i=0;i<m;i++){
    	cin>>x>>y;
    	if(!r[x]) r[x]=1,rnum++;
    	if(!c[y]) c[y]=1,cnum++;
    	cout<<(long long)(n-rnum)*(n-cnum)<<" ";
	}
	return 0;
}

<三>AcWing 4796. 删除序列

一、题目

1、原题链接

4796. 删除序列 - AcWing题库

2、题目描述

给定一个长度为 n 的正整数序列 a1,a2,…,an。

你可以进行任意次删除操作。

每次删除操作分为两步:

  1. 选择序列中的一个元素(不妨设其元素值为 x),并将这一个元素删除,这可以给你加 x 分。
  2. 所有元素值为 x−1 和 x+1 的元素(如果有的话)从序列中删除,这不会给你带来任何分数。

请计算,通过删除操作,你可以获得的最大得分。

输入格式

第一行包含整数 n。

第二行包含 n 个正整数 a1,a2,…,an。

输出格式

一个整数,表示可以获得的最大得分。

数据范围

前 6 个测试点满足 1≤n≤10。
所有测试点满足 1≤n≤10^5,1≤ai≤10^5。

输入样例1:

2
1 2

输出样例1:

2

输入样例2:

3
1 2 3

输出样例2:

4

输入样例3:

9
1 2 1 3 2 2 2 2 3

输出样例3:

10

二、解题报告

思路来源:AcWing 4796. 删除序列(AcWing杯 - 周赛) - AcWing

y总yyds

1、思路分析

1)dp[i]代表从数字1,2,3...一直到数字i的序列通过删除操作可以获得的最大得分(无论这个范围内某个数字是否出现过)。a[i]代表删除数字i后的得分,也就是数字i的出现次数乘数字i的价值(针对本题数字i的价值就是i的数值)。

2)dp[i]可以有两种情况递推出来,第一种情况是不删除数字i,从数字i-1开始删,第二种情况是删除数字i,下一个元素从数字i-2开始删。所以dp[i]=max(dp[i-1],dp[i-2]+a[i])

3)dp[1]代表只有1个数字1,所以dp[1]的最大得分就是删除数字1,所以dp[1]初始化为a[1],即删除数字1的得分。

4)我们要求的是从数字1一直到数字10^5的序列的最大得分(因为给出的数字范围是1≤ai≤10^5,即输入的数字可能为这个范围内的任何一个数),所以输出dp[100000],即为所求。

2、时间复杂度

时间复杂度为O(n)

3、代码详解 

#include <iostream>
using namespace std;
long long dp[100010];
long long a[100010];//代表删除每个数后可以获得的得分 
int main()
{   int n;
    cin>>n; 
    long long t;
    for(int i=1;i<=n;i++){
    	cin>>t;
    	//若数字重复出现,得分累加 
    	a[t]+=t;
	}
	//序列长度为1,删除数字1,得分最大 
	dp[1]=a[1];
	for(int i=2;i<=100010;i++){
		//遍历所有可能出现的数字 
		dp[i]=max(dp[i-1],dp[i-2]+a[i]);
	}
	cout<<dp[100000];
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

马看到什么是人决定的

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

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

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

打赏作者

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

抵扣说明:

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

余额充值