- 题解
题解 2024新学期欢乐赛
- 2024-2-29 21:21:57 @
T1 卖水果
难度:学过分支就能拿到满分,刚入门学过输入输出也可以得到30分。
30分做法:根据数据范围,有30%数据“保证做成果酱收益最高”,直接输出 n/10*x*4 即可完成。或者依据另外30%数据“保证做成沙拉收益最高”,直接输出 n/2*y 也可获得30分。
满分做法:题目中一共有三种售卖方式,分别计算出三种方式的收益同时记录最大值输出即可,且n一定是10的倍数,因此也无需考虑不能整除的情况,标程如下:
#include <bits/stdc++.h>
using namespace std;
int n, x, y;
int a1, a2, a3, a4;
int main()
{
cin >> n >> x >> y;
cin >> a1 >> a2 >> a3 >> a4;
int plan1 = (n / 10) * 4 * x;
int plan2 = (n / 2) * y;
int plan3 = (a1 + a2 + a3 + a4) * n;
if (plan1 > plan2 && plan1 > plan3){
cout << plan1 << "\n";
}
else if (plan2 > plan3){
cout << plan2 << "\n";
}
else{
cout << plan3 << "\n";
}
return 0;
}
T2 算得分
难度:使用简单的嵌套循环,并会使用循环求解次方以及寻找最值就能拿到满分。仅仅会使用分支和单层循环可以拿到60分。
60分做法:数据中有30%保证n~i~=0,这种情况说明仅仅提交了当前这次,直接将s~i~加入总分即可;还有30%保证 n~i~=10,则可以直接按照 si*7/10 计算并加入总分。综上,在完成输入的同时去判断 ni 的是0还是10并计算对应结果计入总分,最终输出总分,便可得到60分。
满分做法:首先循环T次完成输入,对于每一组s~i~和n~i~,将s*7/10的结果与通过循环n次s=s*95/100算出的结果作比较,其中较大值计入总分即可,标程如下:
#include <bits/stdc++.h>
using namespace std;
int T, s, n, sum;
int main()
{
cin >> T;
while (T--)
{
cin >> s >> n;
int base = s * 7 / 10;
for (int i = 1; i <= n; i++)
s = s * 95 / 100;
sum += max(s, base);
}
cout << sum << "\n";
return 0;
}
T3 WOTOJO
难度:需要学过字符串并找到正确的枚举策略可以拿到满分。
30分做法:依据数据中的子任务2,有30%的数据保证s中仅有一个子序列是wotojo,因此我们只需要找到第一个w的位置和最后一个o的位置便能求得答案。
满分做法:枚举策略为遍历字符串,枚举出每一个w为开头的包含“wotojo”子序列的最短子串长度,同时记录最小值。具体做法如下:
#include <bits/stdc++.h>
using namespace std;
string s , t = "wotojo";
int main()
{
cin >> s;
int ans = s.size();
for (int i = 0; i < s.size(); i++)// 注意字符串下标从0开始
{
if (s[i] != 'w') // 找到 w 才开始往后扫
continue;
int now = 1; // 下一个要查询的字符为 t[now]
for (int j = i + 1; j < s.size(); j++)
{
// 匹配上最近的一个
if (s[j] == t[now]) //当前字符匹配上之后寻找下一个字符
now++;
if (now == 6)
{
// 到 j 的位置时六个字符都找到了
// 即 s[i] ~ s[j] 这个子串中存在子序列 wotojo
// 显然这是 i 开头最短的子串
ans = min(ans, j - i + 1);
break;
}
}
}
cout << ans << "\n";
return 0;
}
T4 三子棋
难度:需要熟练掌握二维数组以及枚举思想并有一定的程序优化能力。
满分做法:首先需要确定枚举的策略来确保不会重复或遗漏,对于每一个三连来说都有三个位置的棋子,即两个端点和一个中间点,那么我们可以枚举当前这个没有放棋子的位置作为端点或作为中间点能否横着、竖着或斜着构成三连。作为端点一共有8个方向可以延伸出去,即上、右上、右、右下、下、左下、左、左上,而作为中间点有4个方向可以延伸,即横、竖、左斜、右斜。对于每种情况通过下标的改变和数组调用,判断对应位置是否已落子即可记录出最终的解。标程如下:
#include <bits/stdc++.h>
using namespace std;
int n, m;
char g[55][55];
// 从下标为 1 开始,分别记录 8 个方向的下标变化。
// 左上、上、右上、左、右、左下、下、右下。
int dx[] = {0, -1, -1, -1, 0, 0, 1, 1, 1};
int dy[] = {0, -1, 0, 1, -1, 1, -1, 0, 1};
int main()
{
cin >> n >> m;
// 为了避免减 2 造成数组越界,下标从 2 开始输入
for (int i = 2; i <= n + 1; i++)
for (int j = 2; j <= m + 1; j++)
cin >> g[i][j];
int ans = 0;
for (int i = 2; i <= n + 1; i++)
for (int j = 2; j <= m + 1; j++)
{
if (g[i][j] == '#')
continue;
bool flag = false;
// 作为端点的八个方向
for (int k = 1; k <= 8; k++)
{
int x = i + dx[k];
int y = j + dy[k];
int xx = i + 2 * dx[k];
int yy = j + 2 * dy[k];
if (g[x][y] == '#' && g[xx][yy] == '#')
{
flag = true;
break;
}
}
if (flag)
{
ans++;
continue;
}
// 作为中间点的四个方向
for (int k = 1; k <= 4; k++)
{
// 两个棋子方向正相反
int x = i + dx[k];
int y = j + dy[k];
int xx = i - dx[k];
int yy = j - dy[k];
if (g[x][y] == '#' && g[xx][yy] == '#')
{
flag = true;
break;
}
}
if (flag)
ans++;
}
cout << ans << "\n";
return 0;
}