传送门
A. Bad Triangle
题意:
给出一个不降的序列 \(a\), 要求判断是否能在其中找出三个下标递增且不能组成三角形的数,
能则输出三个下标,否则输出 \(-1\)。
题解:
贪心思考怎样最容易凑不出三角形,选择前两个和最后一个即可,此时若凑出了三角形就输出 \(-1\)。
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define SZ(a) (int)((a).size())
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> Pii;
typedef pair <ll, int> Pli;
typedef unsigned long long ull;
const double eps = 1e-8;
const int mod = (int)(1e9) + 7;
const int inf = 0x7fffffff;
const int N = (int)(5e4) + 7;
int _, n, a[N];
int main() {
// freopen("in.in", "r", stdin);
for (scanf("%d", &_); _; --_) {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
if (a[1] + a[2] <= a[n]) printf("1 2 %d\n", n);
else puts("-1");
}
return 0;
}
B. Substring Removal Game
题意:
给出一个 \(01\) 串,从 Alice 开始,和 Bob 轮流操作,
每次操作可以移除任意长度连续且元素都相等的子串,
最后得分是自己移除所有子串中 \(1\) 的个数总和,
每人都会以选择最优的策略,求 Alice 的得分。
题解:
既然都是最优策略,每人肯定都只会优先移除连续的 \(1\),
所以把连续的 \(1\) 按个数记录到数组里,从大到小排序,再从第一个开始跳着选即是 Alice 的答案。
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define SZ(a) (int)((a).size())
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> Pii;
typedef pair <ll, int> Pli;
typedef unsigned long long ull;
const double eps = 1e-8;
const int mod = (int)(1e9) + 7;
const int inf = 0x7fffffff;
const int N = (int)(2e5) + 7;
int _, n;
char s[N];
int one[N], cnt;
int main() {
// freopen("in.in", "r", stdin);
for (scanf("%d", &_); _; --_) {
cnt = 0;
scanf("%s", s + 1);
n = strlen(s + 1);
for (int i = 1; i <= n; ++i) {
if (s[i] == '1') {
if (s[i - 1] != '1') one[++cnt] = 1;
else ++one[cnt];
}
}
sort(one + 1, one + 1 + cnt, greater<int>());
int res = 0;
for (int i = 1; i <= cnt; i += 2) res += one[i];
printf("%d\n", res);
}
return 0;
}
C. Good Subarrays
题意:
给出一个由 \([0, 9]\) 的数字构成的数字串 \(a\),给出好子串的定义:
- 对于连续子串 \(a_l, a_{l + 1} \dots a_{r - 1}, a_r\),
满足 \(\sum_{i = l}^r a_i = r - l + 1\)
求该序列中有多少好串。
题解:
对于这种可以整体扫一遍的区间计数问题,
一种常见的分类就是首先外层的 \(O(n)\) 枚举 \(i\), 再 \(O(1) 或 O(nlogn)\) 计算出以 \(i\) 为有端点的指定区间个数。
我的思路是首先求一遍前缀和 \(pre\), 将题意转化为求满足 \(1 \leq l < r \leq n\) 且 \(pre_r - pre_{l - 1} = r - l + 1\) 的 \((l, r)\) 对数。
将上式移项得 \(pre_r - r = pre_{l - 1} - (l - 1)\), \(1 \leq l < r \leq n\)
即 \(pre_r - r = pre_l - l\), \(0 \leq l < r \leq n\)。
此时可令 \(pre_i = pre_i - i, 1 \leq i \leq n\),最后在遍历统计时用 map 记录前 \(i - 1\) 个元素中与第 \(i\) 相等的个数即可。
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define SZ(a) (int)((a).size())
#define all(x) (x).begin(), (x).end()
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> Pii;
typedef pair <ll, int> Pli;
typedef unsigned long long ull;
const double eps = 1e-8;
const int mod = (int)(1e9) + 7;
const int inf = 0x7fffffff;
const int N = (int)(2e5) + 7;
char s[N];
int _, n, a[N], pre[N];
map <int, ll> pm;
int main() {
// freopen("in.in", "r", stdin);
for (scanf("%d", &_); _; --_) {
pm.clear();
scanf("%d%s", &n, s + 1);
for (int i = 1; i <= n; ++i) a[i] = (s[i] ^ 48);
for (int i = 1; i <= n; ++i) pre[i] = pre[i - 1] + a[i];
for (int i = 1; i <= n; ++i) pre[i] -= i;
// for (int i = 1; i <= n; ++i) printf("%d%c", pre[i], " \n"[i == n]);
ll res = 0;
pm[0] = 1;
for (int i = 1; i <= n; ++i) {
res += pm[pre[i]];
++pm[pre[i]];
}
printf("%lld\n", res);
}
return 0;
}