A.Shout Everyday(枚举)
题意:
在 AtCoderAtCoderAtCoder 王国,居民们每天都要在 AAA 点大声喊出他们对章鱼烧的热爱。
住在 AtCoderAtCoderAtCoder 王国的高桥每天 BBB 点睡觉, CCC 点起床( 242424 小时钟)。他醒着的时候可以喊出对章鱼烧的爱,但睡着的时候却不能。判断他是否每天都能喊出对章鱼烧的爱。这里,一天有 242424 小时,而他的睡眠时间小于 242424 小时。
分析:
直接从AAA枚举到BBB,观察是否遍历到CCC即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b, c;
cin >> a >> b >> c;
int flag = 1;
for (; a != b; a = (a + 1) % 24) {
if (a == c) {
flag = 0;
break;
}
}
if (flag)
cout << "Yes" << endl;
else
cout << "No" << endl;
return 0;
}
B.Cut .0(模拟)
题意:
一个实数 XXX 已精确到小数点后第三位。
请在下列条件下打印实数 XXX 。
- 小数部分不能有尾数 “0”。
- 小数点后不能有多余的尾数。
分析:
按照题意模拟即可。
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
while (s.size() > 2 && s.back() == '0') {
s.pop_back();
}
if (s.back() == '.') {
s.pop_back();
}
cout << s << endl;
return 0;
}
C.Enumerate Sequences(dfs)
题意:
按升序排列打印所有满足以下条件的长度为 NNN 的整数序列。
- 第 iii 个元素介于 111 和 RiR_iRi 之间。
- 所有元素之和是 KKK 的倍数。
什么是序列的词序?如果下面的 1. 或 2. 成立,那么序列 A=(A1,…,A∣A∣)A = (A_1, \ldots, A_{|A|})A=(A1,…,A∣A∣) 在词法上小于 B=(B1,…,B∣B∣)B = (B_1, \ldots, B_{|B|})B=(B1,…,B∣B∣) :
- ∣A∣<∣B∣|A| < |B|∣A∣<∣B∣ 和 (A1,…,A∣A∣)=(B1,…,B∣A∣)(A_{1},\ldots,A_{|A|}) = (B_1,\ldots,B_{|A|})(A1,…,A∣A∣)=(B1,…,B∣A∣) .
- 存在一个整数 1≤i≤min{∣A∣,∣B∣}1\leq i\leq \min\{|A|,|B|\}1≤i≤min{∣A∣,∣B∣} ,使得下面两个条件都成立:
- (A1,…,Ai−1)=(B1,…,Bi−1)(A_{1},\ldots,A_{i-1}) = (B_1,\ldots,B_{i-1})(A1,…,Ai−1)=(B1,…,Bi−1)
- Ai<BiA_i < B_iAi<Bi
分析:
我们用dfsdfsdfs按照要求依次搜索即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int n, k, r[15], a[15];
void dfs(int x, int sum) {
if (x == n + 1) {
if (sum % k == 0) {
for (int i = 1; i <= n; i++) {
cout << a[i] << ' ';
}
cout << endl;
}
return;
}
for (int i = 1; i <= r[x]; i++) {
a[x] = i;
dfs(x + 1, sum + i);
}
}
int main(){
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> r[i];
}
dfs(1, 0);
return 0;
}
D.Pedometer (思维)
题意:
一个湖周围有 NNN 个休息区。
这些休息区按顺时针顺序编号为 111 、 222 、…、 NNN 。
从休息区 iii 顺时针走到休息区 i+1i+1i+1 需要 AiA_iAi 步(其中休息区 N+1N+1N+1 指的是休息区 111 )。
从休息区 sss 顺时针走到休息区 ttt ( s≠ts \neq ts=t )所需的最小步数是 MMM 的倍数。
求 (s,t)(s,t)(s,t) 的可能对数。
分析:
当s→ts \rightarrow ts→t有两种路径,s<ts < ts<t 时,我们有pre[t]−pre[s]≡0(modM)pre[t] - pre[s] \equiv 0(mod M)pre[t]−pre[s]≡0(modM)。当s>ts > ts>t时,我们有pre[t]+pre[n]−pre[s]≡0(modM)pre[t] + pre[n] - pre[s] \equiv 0(mod M)pre[t]+pre[n]−pre[s]≡0(modM)。移项后有pre[t]≡pre[s]−pre[n](modM)pre[t] \equiv pre[s] - pre[n] (mod M)pre[t]≡pre[s]−pre[n](modM)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int n, m;
cin >> n >> m;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<LL> pre(n + 1);
for (int i = 0; i < n; i++) {
pre[i + 1] = pre[i] + a[i];
}
LL ans = 0;
map<int, int> mp;
for (int i = 0; i < n; i++) {
ans += mp[((pre[i] - pre[n]) % m + m) % m];
ans += mp[pre[i] % m];
mp[pre[i] % m]++;
}
cout << ans << endl;
return 0;
}
E.Permute K times (倍增)
题意:
给你一个长度为 NNN 的序列 XXX ,其中每个元素都在 111 和 NNN 之间(包括首尾两个元素),以及一个长度为 NNN 的序列 AAA 。请输出在 AAA 上执行以下操作 KKK 次的结果。
- 用 BBB 替换 AAA ,使得 Bi=AXiB_i = A_{X_i}Bi=AXi .
分析:
将题目转化成给定基环森林,点有点权。问从每个点出发,走了kkk步后的点的点权。其中边是i→xii \rightarrow x_ii→xi,点权aia_iai。问第kkk步后到达的点。我们预处理出倍增数组 tmp[i][j]tmp[i][j]tmp[i][j]表示从点jjj出发走了2i2^i2i 步后到达的点。然后对于每个点用倍增数组求kkk次后的结果即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int n;
LL k;
cin >> n >> k;
vector<vector<int> > tmp(64, vector<int>(n));
for (int i = 0; i < n; i++) {
int v;
cin >> v;
v--;
tmp[0][i] = v;
}
vector<int> a(n);
for (auto &x: a)
cin >> x;
for (int i = 1; i < 64; i++) {
for (int j = 0; j < n; j++) {
tmp[i][j] = tmp[i - 1][tmp[i - 1][j]];
}
}
for (int i = 0; i < n; i++) {
LL cnt = k;
int cur = i;
for (int j = 0; j < 64; j++) {
if (cnt & (1LL << j)) {
cur = tmp[j][cur];
}
}
cout << a[cur] << " ";
if (i == n - 1)
cout << endl;
}
return 0;
}
F.Rearrange Query (哈希)
题意:
给你长度为 NNN 的正整数序列: A=(A1,A2,…,AN)A=(A_1,A_2,\ldots,A_N)A=(A1,A2,…,AN) 和 B=(B1,B2,…,BN)B=(B_1,B_2,\ldots,B_N)B=(B1,B2,…,BN) .
给你 QQQ 个查询,让你按顺序处理。
- 给定正整数 li,ri,Li,Ril_i,r_i,L_i,R_ili,ri,Li,Ri 。如果可以重新排列子序列 (Ali,Ali+1,…,Ari)(A_{l_i} , A_{l_i+1}, \ldots , A_{r_i})(Ali,Ali+1,…,Ari) 以匹配子序列 (BLi,BLi+1,…,BRi)(B_{L_i} , B_{L_i+1} , \ldots , B_{R_i})(BLi,BLi+1,…,BRi) ,则输出
Yes,否则输出No。
分析:
如果A[l,r]A[l,r]A[l,r]序列的能通过重排得到B[L,R]B[L,R]B[L,R],首先要满足r−l=R−Lr−l=R−Lr−l=R−L,再观察每个数的出现次数是否一致。存在一个降低计算代价的必要条件是suma[l,r]=sumb[L,R]sum_a[l,r]=sum_b[L,R]suma[l,r]=sumb[L,R],但不是充分条件,会有误判的概率,
但是因为我们只要求数量相等,所以我们事先对所有数进行一个随机映射,那么这个误判的概率将极大减小。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
ULL rnd() {
static ULL A = 1 << 16 | 3, B = 333333331, C = 2341;
return C = A * C + B;
}
int main() {
int n, q;
cin >> n >> q;
vector<LL> a(n);
vector<LL> b(n);
map<LL, LL> mp;
for (auto &x: a) {
cin >> x;
if (mp.find(x) == mp.end()) {
mp[x] = rnd();
}
}
for (auto &x: b) {
cin >> x;
if (mp.find(x) == mp.end()) {
mp[x] = rnd();
}
}
auto presum = [&](vector<LL> &a) {
int n = a.size();
vector<LL> s1(n + 1);
for (int i = 0; i < n; ++i) {
s1[i + 1] = (s1[i] + mp[a[i]]);
}
return s1;
};
auto pa1 = presum(a);
auto pb1 = presum(b);
auto sum = [&](vector<LL> &s, int l, int r) { return (s[r] - s[l - 1]); };
auto check = [&](int l, int r, int L, int R) {
auto PA = sum(pa1, l, r);
auto PB = sum(pb1, L, R);
return PA == PB;
};
while (q--) {
int l, r, L, R;
cin >> l >> r >> L >> R;
if (r - l == R - L && check(l, r, L, R)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}
赛后交流
在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。
群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

1495

被折叠的 条评论
为什么被折叠?



