下面的内容不包括题目翻译,要想获取题目翻译,请参照 这篇教程 来获取题目翻译。
A
题目
看看哪一个 i i i 满足 C = A + B C_ = A+B C=A+B 就可以了,如果满足,输出这个 i i i 就可以走人了。
AC Code:
#include <iostream>
using namespace std;
int n, a, b;
int c[101000];
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 >> c[i];
if (c[i] == a + b) {
cout << i;
return 0;
}
}
return 0;
}
B
题目
我们发现, H H H 和 W W W 都很小,所以我们枚举垂直移动的次数和水平移动的次数。
我们用一个
t
e
m
p
temp
temp 数组来记录当前移动后的地图,设我们执行了
x
x
x 次水平移动和
y
y
y 次垂直移动,那么我们的
t
e
m
p
temp
temp 数组应该长这样:
∑
i
=
1
H
∑
j
=
1
W
t
e
m
p
i
j
=
A
(
(
i
+
x
−
1
)
mod
H
)
(
(
j
+
y
−
1
)
mod
W
)
\sum_{i=1}^H\sum_{j=1}^W temp_{ij}=A_{((i+x-1)\text{mod}H)((j+y-1)\text{mod}W)}
i=1∑Hj=1∑Wtempij=A((i+x−1)modH)((j+y−1)modW)
这里下标从
1
1
1 开始。
解释一下原理:
每一次执行水平移动, A ( i + 1 ) j A_{(i+1)j} A(i+1)j 会变成原来的 A i j A_{ij} Aij,而 A 1 j A_{1j} A1j 会变成原来的 A N j A_{Nj} ANj,相当于第一个下标统一加上一再模上 H H H,每一次垂直移动, A i j + 1 A_{ij+1} Aij+1 会变成 A i j A_{ij} Aij,而 A i 1 A_{i1} Ai1 会变成 A i W A_{iW} AiW,相当于第二个下标统一加上一再模上 W W W。如此这样分别做 x x x 次和 y y y 次就是我们上面的式子。
最后判断一下是不是每一个 B i j B_{ij} Bij 等于 t e m p i j temp_{ij} tempij 就可以了。
AC Code:
#include <iostream>
using namespace std;
int h, w;
char a[1010][1010], b[1010][1010];
char tmp[1010][1010];
bool check(int s, int t) {
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
tmp[i][j] = a[(i + s - 2) % h + 1][(j + t - 2) % w + 1];
if (tmp[i][j] != b[i][j]) return 0;
}
}
return 1;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> h >> w;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) cin >> a[i][j];
}
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) cin >> b[i][j];
}
for (int s = 1; s <= h; s++) {
for (int t = 1; t <= w; t++) {
if (check(s, t)) {
cout << "Yes";
return 0;
}
}
}
cout << "No";
return 0;
}
C
题目
这里我们枚举一每一个点为中心的叉即可。我们判断出这个叉的大小,对应大小的计数器加上一。最后输出计数器里的内容即可。
为了算出每一个点为中心的叉的大小,我们先假设这个叉大小为 0 0 0,如果当前大小的叉存在,那么扩大叉的范围,再试。由于对于每一个大小的叉,之前大小的叉已经试过了,每一次尝试只有 O ( 1 ) O(1) O(1) 的时间复杂度。而叉的大小不超过 min ( H , W ) \min(H,W) min(H,W),所以计算以每一个点为中心的叉的大小的时间复杂度是 min ( H , W ) \min(H,W) min(H,W)
3 ≤ H , W ≤ 100 3 \le H,W \le 100 3≤H,W≤100,枚举点 H W HW HW 个,一个 min ( H , W ) \min(H,W) min(H,W),极限情况下是 1 0 6 10^6 106,合法的时间复杂度。
AC Code:
#include <iostream>
using namespace std;
int h, w;
char c[200][200];
int cnt[200];
int check(int x, int y) {
int d = 0;
while (x + d <= h && x - d >= 1 && y + d <= w && y - d >= 1 && c[x + d][y + d] == '#' && c[x - d][y + d] == '#' && c[x + d][y - d] == '#' && c[x - d][y - d] == '#') d++;
return d - 1;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> h >> w;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) cin >> c[i][j];
}
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
cnt[check(i, j)]++;
}
}
for (int i = 1; i <= min(h, w); i++) cout << cnt[i] << ' ';
return 0;
}
D
题目
此题预处理出质数,一个一个枚举 a , b , c a,b,c a,b,c,由于 N ≤ 1 0 1 2 N \le 10^12 N≤1012,这样枚举大概只有 N 3 5 N^{\frac{3}{5}} N53 的时间复杂度,预处理出质数,处理到 ( N ) \sqrt(N) (N) 的质数是没问题的。预处理质数用最朴素的试除法,时间复杂度不大, O ( N N ) O(\sqrt{N}\sqrt{\sqrt{N}}) O(NN),大约 1 0 9 10^9 109,可以在 3 3 3 秒钟的时间内解决。
AC Code:
#include <iostream>
#define int long long
using namespace std;
int n;
int cnt, cntt;
int primes[1000100];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 2; i <= 1000000; i++) {
bool flag = 0;
for (int j = 2; j * j <= i; j++) {
if (i % j == 0) {
flag = 1;
break;
}
}
if (!flag) primes[++cntt] = i;
}
for (int i = 1; primes[i] * primes[i] * primes[i] * primes[i] * primes[i] <= n; i++) {
for (int j = i + 1; primes[i] * primes[i] * primes[j] * primes[j] * primes[j] <= n; j++) {
for (int k = j + 1; primes[i] * primes[i] * primes[j] * primes[k] * primes[k] <= n; k++) {
cnt++;
}
}
}
cout << cnt;
return 0;
}
E
多用 AtCoder Library。
题目
核心:记忆化搜索。
我们直接上记忆化动态规划,如果这个条件试过了,就直接退出。这个过程中只有是 2 , 3 , 5 2,3,5 2,3,5 的倍数的数会被枚举。再 N N N 取到极限范围用容斥原理算一下有多少个:
log 2 N log 3 N log 5 N \log_2^N\log_3^N\log_5^N log2Nlog3Nlog5N
这个式子大概在 N N N 为 1 0 1 8 10^18 1018 的情况下,不会超过 1 0 6 10^6 106。
套上一个 mod998244353
秒掉。
对于每一个
d
p
i
dp_i
dpi,记录符合条件的和所有数字的情况的比值。
如果
i
≥
N
i\ge N
i≥N:
如果
i
=
N
i=N
i=N,那么
d
p
i
=
1
dp_i=1
dpi=1,否则
d
p
i
=
0
dp_i=0
dpi=0。
否则:
d
p
i
dp_i
dpi 为
d
p
2
i
d
p
3
i
d
p
4
i
d
p
5
i
d
p
6
i
5
\frac{dp_{2i}dp_{3i}dp_{4i}dp_{5i}dp_{6i}}{5}
5dp2idp3idp4idp5idp6i,由于
1
1
1 乘上任何数还是它自己,所以没必要算。正确答案是
d
p
1
dp_1
dp1。
如果不会用 AtCoder Library 的,也可以自己写一个分数加减法套上扩展欧几里得。
AC Code:
#include <iostream>
#include <atcoder/all>
#include <map>
#define int long long
using namespace std;
using namespace atcoder;
using mint = modint998244353;
int n;
map<int, mint> dp;
mint sol(int now) {
if (now >= n) return now == n ? 1 : 0;
if (dp.count(now)) return dp[now];
mint ret = 0;
for (int i = 2; i <= 6; i++) ret += sol(i * now);
return dp[now] = ret / 5;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
cout << sol(1).val();
return 0;
}