AcWing-周赛86
一、健身
【题目】
李华一共要进行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
【解题思路】
模拟
三个数据一组:chest: i % 3 == 0;biceps: i % 3 == 1;back: i % 3 == 2;
【代码】
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int sum[3] = {0}; // 0-chest , 1-biceps , 2-back
int n;
cin >> n;
for (int i = 0; i < n; i ++)
{
int a;
cin >> a;
sum[i % 3] += a;
}
int chest = sum[0] , biceps = sum[1] , back = sum[2] ;
sort(sum , sum + 3);
if (sum[2] == chest) cout << "chest" ;
else if (sum[2] == biceps) cout << "biceps" ;
else cout << "back" ;
return 0;
}
二、安全区域
【题目】
给定一个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≤105,1≤m≤min(105,n2),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
【解题思路】
类似于小学数学的面积平移的问题(在一个长方形花园中修路,求剩余面积的问题)。
令row = n ,col = n,输入一组x,y 就减一,不会被攻击的方格的数量=row×col。
注:若开一个105×105二维数组,数组会炸!!!
【代码】
#include <iostream>
#include <algorithm>
using namespace std;
bool a[100010] , b[100010] ;
int main()
{
int n, m;
cin >> n >> m;
int row = n, col = n;
while (m --)
{
int x, y;
cin >> x >> y;
if (!a[x]) a[x] = 1, row --;
if (!b[y]) b[y] = 1, col --;
cout <<(long long)row * col << ' ' ;
}
return 0;
}
三、删除序列
【题目】
给定一个长度为n的正整数序列a1,a2,…,an。
你可以进行任意次删除操作。
每次删除操作分为两步:
- 选择序列中的一个元素(不妨设其元素值为x),并将这一个元素删除,这可以给你加x分。
- 将所有的元素值为x−1和x+1的元素(如果有的话)从序列中删除,这不会给你带来任何分数。
请计算,通过删除操作,你可以获得的最大得分。
输入格式
第一行包含整数n。
第二行包含n个正整数a1,a2,…,an。
输出格式
一个整数,表示可以获得的最大得分。
数据范围
前6个测试点满足1≤n≤10。
所有测试点满足1≤n≤105,1≤ai≤105。
输入样例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
【解题思路】
dp
最大收益→相同的数,要么全选,要么不选
设a[ i ]为所有数字i的价值,k个i→s[ i ] = k * i;
设f[ i ]为1至 i 获得的最大收益
状态转移方程:f[ i ] = max ( f[i – 1] , f[i – 2] + a[i] )
【代码】
#include <iostream>
using namespace std;
const int N = 100010;
long long a[N], f[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i ++ )
{
int x;
cin >> x;
a[x] += x;
}
f[1] = a[1];
for (int i = 2; i <= 100000; i ++ )
f[i] = max(f[i - 1], f[i - 2] + a[i]);
cout << f[100000] ;
return 0;
}