比赛链接:
https://ac.nowcoder.com/acm/contest/11221
A.深渊水妖
思路:
找到每一个非递减的区间,然后将最大的找出来,输出就行,简单水题,比赛的时候连题目都理解错了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define pb push_back
#define PII pair <int, int>
#define se second
const int N = 3e6 + 10;
int n, a[N], T;
void solve(){
cin >> n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int i = 1, j = 1, ans = 0;
vector <PII> v;
while (j <= n){
while (j < n && a[j] <= a[j + 1])
j++;
if (a[j] - a[i] >= ans){
if (a[j] - a[i] > ans){
ans = a[j] - a[i];
v.clear();
}
v.pb({i, j});
}
i = ++j;
}
for (auto x : v)
cout << x.fi << " " << x.se << " ";
cout << "\n";
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
B.顽皮恶魔
思路:
直接遍历所有植物,判断周围有没有保护伞,要注意一下边界,可以初始化一下。
代码:
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define pb push_back
#define PII pair <int, int>
#define se second
const int N = 1e3 + 10;
int n, m, T, dx[9] = {-1, -1, -1, 0, 0, 0, 1, 1, 1}, dy[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
char a[N][N];
void init(int n, int m){
for (int i = 1; i <= n + 1; i++)
for (int j = 1; j <= m + 1; j++)
a[i][j] = '.';
}
void solve(){
cin >> n >> m;
init(n, m);
int ans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (a[i][j] == 'P'){
int f = 1;
for (int k = 0; k < 9; k++){
int x = i + dx[k], y = j + dy[k];
if (a[x][y] == '*'){
f = 0;
break;
}
}
if (f) ans++;
}
cout << ans << "\n";
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
C.绝命沙虫
思路:
就按照题目说的操作就行了,主要是卡了精度,解决的办法有两个,可以分别输入 \(m\) 的整数部分和小数部分然后求和,也可以用接近 1 的数替换掉 1 防止卡精度。
代码:
分别读入
#include <bits/stdc++.h>
using namespace std;
int n, T, m, k;
void solve(){
scanf("%d%d.%d", &n, &m, &k);
int ans = 0, r, g;
while (n > 0){
r = n * 100, g = min(10000, n * 10 * ((m - 1) * 10 + k));
ans += r / 10 + g / 10;
n /= 2;
}
cout << ans << "\n";
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
替换
#include <bits/stdc++.h>
using namespace std;
int n, T;
double m;
void solve(){
cin >> n >> m;
int ans = 0, r, g;
while (n > 0){
r = n * 100, g = min(10000.0, n * 100 * (m - 0.99999));
ans += r / 10 + g / 10;
n /= 2;
}
cout << ans << "\n";
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
D.丛林木马
思路:
容易发现答案就是 \(a * b.size() + b * a.size()\)(a.size() 就是 a 的长度),需要高精,直接上 \(python\)。
代码:
t = int(input())
for i in range(t):
a, b = input().split()
print((int(a) * len(b) + int(b) * len(a)) % 998244353)
E.变异蛮牛
思路:
长度只有可能是 0 或者 1。
设树中黑点的数量为 cnt,那么容易想到答案就是 \(C_{cnt}^2\) + cnt ,因为任意两个黑点作为边的话,其长度必定为 1,而链中只有一个黑点的时候,其长度也为 1。
黑点的数量我们可以通过树的搜索(bfs,dfs等)去求。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
const int N = 3e6 + 10;
LL T, n, u, v, cnt, val[N];
vector <int> e[N];
void dfs(int f, int p){
if (p == 1) cnt++;
for (auto x : e[f]){
if (val[x]) continue;
val[x] = 1;
dfs(x, 1 - p);
}
}
void solve(){
cin >> n;
cnt = 0;
for (int i = 1; i <= n; i++)
e[i].clear(), val[i] = 0;
for (int i = 1; i < n; i++){
scanf("%lld%lld", &u, &v);
e[u].pb(v);
e[v].pb(u);
}
val[1] = 1;
dfs(1, 1);
cout << (cnt * (cnt - 1)) / 2 + cnt << "\n";
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}
F.幽暗统领
思路:
记 \(s\) 为 \(\sum_{i = 1}^n a_i\),mn 为 \(max (\sum_{i = 1}^n a_i)\),res 为 \(s - mn\)。
首先要了解树的重心的定义,我们可以知道,当 \(mn * 2 <= s\) 的时候,所有点都可以作为重心。
如果我们设某个链的第 \(i\) 个节点为重心,这条链中左边的节点有 \(a\) 个,右边的节点有 \(b\) 个。我们可以通过把其它链挂在该节点上的操作,使重心落在第 \(i\) 个节点上。
当 \(mn * 2 > s\) 时,重心一定落在最长的那条链上的某个区间内,接下来就是求这个区间。
根据现有的条件我们可以知道 \(a + b + 1 = mn\),要让重心落在最左边的 \(i\) 上,我们要让左右两边的节点数量尽可能接近,让 \(res + a = b\),那么我们就可以得到 \(a = (mn - res - 1) / 2\) 的关系,即最左边的点就是 \((mn - res - 1) / 2\),右边的节点是和左边的对称的,区间长度就求出来了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 3e6 + 10;
LL T, n, a[N];
void solve(){
scanf("%lld", &n);
LL s = 0, mn = 0;
for (int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
s += a[i];
mn = max(mn, a[i]);
}
if (mn * 2 <= s) cout << s << "\n";
else{
LL res = s - mn, a = (mn - res + 1) / 2, b = mn - a + 1;
cout << b - a + 1 << "\n";
}
}
int main(){
cin >> T;
while (T--)
solve();
return 0;
}