下面的内容不包括题目翻译,要想获取题目翻译,请参照 这篇教程 来获取题目翻译。
A
题目
我们对于每一个 A i A_i Ai 判断可不可以被 K K K 整除,即除以 K K K 是否为 0 0 0,如果是,输出 A i A_i Ai。
AC Code:
#include <iostream>
using namespace std;
int n, k, a[110];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (a[i] % k == 0) cout << a[i] / k << ' ';
}
return 0;
}
B
题目
我们可以使用 STL(Standard Library) 里面的 map
来完成这个问题:对于每一个字串,判断是否出现过,没有出现过答案加一,并将这个字串标记为出现过。
一些语法:
s.substr(a, b); 截取 s 从 a 开始长度为 b 的字串。
map<string, bool> m; 创建一个 map 数组,其中每一个 string 都对应一个 bool 变量,使用:m[s]。
AC Code:
#include <iostream>
#include <cstring>
#include <map>
using namespace std;
string s;
map<string, bool> m;
int ans;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> s;
for (int i = 0; i < (int)s.size(); i++) {
for (int j = 1; i + j <= (int)s.size(); j++) {
if (!m[s.substr(i, j)]) {
ans++;
m[s.substr(i, j)] = 1;
}
}
}
cout << ans;
return 0;
}
C
题目
对于这道题,我们只用关心这些日子在一周中的相对位置就可以了。
我们发现:将这些日子的相对位置从小到大排序后,如果有两个日子之间的差大于 B B B,那么我们完全把这些工作日安排在这 B B B 天内。最后一个日子和第一个日子加上 A + B A+B A+B 天后的差大于 B B B 天,我们也可以得到一个合法解。
AC Code:
#include <algorithm>
#include <iostream>
using namespace std;
int n;
long long a, b;
long long d[200100];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> a >> b;
for (int i = 1; i <= n; i++) cin >> d[i];
for (int i = 1; i <= n; i++) {
d[i] %= (a + b);
}
sort(d + 1, d + n + 1);
d[n + 1] = d[1] + a + b;
for (int i = 2; i <= n + 1; i++) {
if (d[i] - d[i - 1] > b) {
cout << "Yes";
return 0;
}
}
cout << "No";
return 0;
}
D
题目
要解决这个问题,你首先要知道位运算是什么,如果不知道可以跳过这道题。
首先,我们判断无解的情况:
如果 a + b < popcount ( C ) a+b<\text{popcount}(C) a+b<popcount(C),那么无论怎么构造,都达不到 C C C。
然后我们创造一种构造方法,使得这种构造方法可以在有解情况下一定可以构造出正解。
我们先来处理 C C C 中 1 1 1 的情况,拿第一个样例举例:
a = 3, b = 4, C = 00000111
我们先来看 C C C 中第 1 , 2 , 3 1,2,3 1,2,3 位,再看为 0 0 0 的地方。如果 C C C 的第 i i i 位为 0 0 0,那么这一位可以通过两种方式得到:两个 0 0 0 和两个 1 1 1。我们想让 X X X 和 Y Y Y 构造完 1 1 1 的地方后剩余的 1 1 1 的数量相等以方便构造 0 0 0,所以我们每碰到一个 1 1 1 就让剩余 1 1 1 个数较大的那个数这一位为 1 1 1。如果剩余的 1 1 1 的数量不一样就说明无解。
再看异或的情况:如果 C C C 这一位为 0 0 0,且 a a a 和 b b b 都不为 0 0 0,那么让 X X X 和 Y Y Y 这一位都变为 1 1 1。如果构造完后还有没有构造的 1 1 1,说明无解。
这样就可以快速地构造出答案。
AC Code:
#include <iostream>
using namespace std;
long long a, b, c;
int cnt;
long long x, y;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> a >> b >> c;
for (int i = 1; i <= 60; i++) cnt += ((c >> (i - 1)) & 1ll);
if (a + b < cnt) {
cout << "-1";
return 0;
}
for (int i = 1; i <= 60; i++) {
if (c & (1ll << (i - 1))) {
if (a > b) {
a--;
x += (1ll << (i - 1));
}
else if (b) {
b--;
y += (1ll << (i - 1));
}
}
}
if (a != b) {
cout << "-1";
return 0;
}
for (int i = 1; i <= 60; i++) {
if (a && b && !(c & (1ll << (i - 1)))) {
a--;
b--;
x += (1ll << (i - 1));
y += (1ll << (i - 1));
}
}
if (a || b) {
cout << "-1";
return 0;
}
cout << x << ' ' << y;
return 0;
}
E
题目
我们发现每一个元素出现的时间都是连续的,我们可以前缀和出集合大小,每一次元素的增减就把
A
A
A 相应的位置加上出现区间内集合的大小。用一个 last
变量维护元素出现位置。最后处理一下出现到查询末尾的元素即可。
用样例举例:
每一个时刻的集合:
{1}
{1,3}
{1}
{1,2}
每一个时刻的集合大小:
1
2
1
2
集合大小的前缀和:
1
3
4
6
每一个值出现位置:
1 -1 -1
1 -1 2
1 -1 -1
1 4 -1
于是 A A A 应该长这样:
A = [ ( s u m 4 − s u m 0 ) , ( s u m 4 − s u m 3 ) , ( s u m 2 − s u m 1 ) ] A=[(sum_4-sum_0),(sum_4-sum_3),(sum_2-sum_1)] A=[(sum4−sum0),(sum4−sum3),(sum2−sum1)]
AC Code:
#include <iostream>
using namespace std;
int n, q;
int x[200100];
long long sum[200100];
int s[200100];
int cnt;
int last[200100];
long long a[200100];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= q; i++) cin >> x[i];
for (int i = 1; i <= q; i++) {
if (!s[x[i]]) {
cnt++;
sum[i] = sum[i - 1] + cnt;
s[x[i]] = 1;
last[x[i]] = i;
}
else {
cnt--;
sum[i] = sum[i - 1] + cnt;
s[x[i]] = 0;
a[x[i]] += sum[i - 1] - sum[last[x[i]] - 1];
}
}
for (int i = 1; i <= n; i++) {
if (s[i]) {
a[i] += sum[q] - sum[last[i] - 1];
}
}
for (int i = 1; i <= n; i++) cout << a[i] << ' ';
return 0;
}