# AtCoder Grand Contest 003

## A - Wanna go back home

#include <cstdio>

const int MN = 100005;

char s[MN];
int a, b, c, d;

int main() {
scanf("%s", s + 1);
for (int i = 1; s[i]; ++i) {
if (s[i] == 'N') ++a;
if (s[i] == 'S') ++b;
if (s[i] == 'E') ++c;
if (s[i] == 'W') ++d;
}
puts((a && !b) || (b && !a) || (c && !d) || (d && !c) ? "No" : "Yes");
return 0;
}


## B - Simplified mahjong

#include <cstdio>

const int MN = 100005;

int N, A[MN];
long long Ans;

int main() {
scanf("%d", &N);
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]);
int lst = 0;
for (int i = 1; i <= N; ++i)
Ans += (A[i] + lst) / 2,
lst = A[i] ? (A[i] + lst) % 2 : 0;
printf("%lld\n", Ans);
return 0;
}


## C - BBuBBBlesort!

#include <cstdio>
#include <algorithm>

const int MN = 100005;

int N, A[MN], B[MN], Ans;

int main() {
scanf("%d", &N);
for (int i = 1; i <= N; ++i) scanf("%d", &A[i]), B[i] = A[i];
std::sort(B + 1, B + N + 1);
for (int i = 1; i <= N; ++i)
Ans += (std::lower_bound(B + 1, B + N + 1, A[i]) - B - i) & 1;
printf("%d\n", Ans >> 1);
return 0;
}


## D - Anticube

1. 如果 $x = 1$，则分解已经完成。
2. 如果 $x = p^2$（这是能够 $\mathcal O (1)$ 进行检测的，假设 sqrt 的时间是常数），则 $y$ 乘上 $p^2$$z$ 乘上 $p$
3. 如果 $x \le \sqrt{{10}^{10}}$，则 $x = p$，则 $y$ 乘上 $p$$z$ 乘上 $p^2$
4. 如果前三种情况均不满足，则说明要么 $x = p > \sqrt{{10}^{10}}$，要么 $x = p q$。此时 $y$ 乘上 $x$，然后
这两种情况下 $z$ 都会乘上 $> {10}^{10}$ 的数值，已经超过值域范围，所以不可能和任何其他类匹配，直接当作 $\infty$ 即可。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <map>

typedef long long LL;
const LL Infll = 0x3f3f3f3f3f3f3f3f;

int N, Ans;
std::map<std::pair<LL, LL>, std::pair<int, int>> mp;

int main() {
scanf("%d", &N);
for (int i = 1; i <= N; ++i) {
LL x, y = 1, z = 1;
scanf("%lld", &x);
for (int j = 2; j <= 2154; ++j) if (x % j == 0) {
int c = 0, d = 0;
while (x % j == 0) x /= j, ++c, d += 2;
c %= 3, d %= 3;
while (c) y *= j, --c;
while (d) z = j <= Infll / z ? z * j : Infll + 1, --d;
}
y *= x;
LL v = sqrt(x);
while (v * v <= x) ++v;
while (v * v > x) --v;
if (v * v == x) z = v <= Infll / z ? z * v : Infll + 1;
else if (x <= 100000) z = x * x <= Infll / z ? z * x * x : Infll + 1;
else z = Infll;
if (y == 1) Ans = 1;
else if (y <= z) ++mp[{y, z}].first;
else ++mp[{z, y}].second;
}
for (auto p : mp) Ans += std::max(p.second.first, p.second.second);
printf("%d\n", Ans);
return 0;
}


## E - Sequential operations on Sequence

$N$ 塞进 $q$ 序列的开头（这会让一些后续讨论更简单）。然后，容易发现如果 $q_i \ge q_j$$i < j$），则把 $q_i$ 删掉是更优的。

1. 找到 $A[1 \sim (i - 1)]$ 中从后往前数第一个小于等于 $k$ 的位置 $A[p]$
2. 如果找不到，也就是 $k < A[1]$，那么说明已经转移到头了，直接给最终答案的 $b[1 \sim k]$ 加上 $v$ 就行。
3. 让当 $i = p$ 时的 $b$ 数组的 $b[1 \sim A[p]]$ 加上 $\displaystyle v \cdot \left\lfloor \frac{k}{A[p]} \right\rfloor$，由于 $A$ 是递增的，可以使用二分查找。
4. $k \gets k \bmod A[p]$。回到第 1 步。

#include <cstdio>
#include <algorithm>

typedef long long LL;
const int MN = 100005, MQ = 100005;

int N, Q, tp;
LL A[MQ], t[MQ], Ans[MN];

int main() {
scanf("%d%d", &N, &Q);
if (!Q) {
for (int i = 1; i <= N; ++i) puts("1");
return 0;
}
A[tp = 1] = N;
for (int i = 1; i <= Q; ++i) {
LL x;
scanf("%lld", &x);
while (tp && A[tp] >= x) --tp;
A[++tp] = x;
}
t[tp] = 1;
for (int i = tp; i >= 2; --i) {
LL k = A[i];
t[i - 1] += k / A[i - 1] * t[i], k %= A[i - 1];
while (k >= A[1]) {
int p = std::upper_bound(A + 1, A + tp + 1, k) - A - 1;
t[p] += k / A[p] * t[i], k %= A[p];
}
Ans[k] += t[i];
}
Ans[A[1]] += t[1];
for (int i = N; i >= 1; --i) Ans[i] += Ans[i + 1];
for (int i = 1; i <= N; ++i) printf("%lld\n", Ans[i]);
return 0;
}


## F - Fraction of Fractal

$0$ 阶分形，有 $1$ 个黑色格子，有 $0$ 个相邻的黑色格子对，那么我们考虑这样的矩阵快速幂：

$\begin{bmatrix} a & \\ b & c \end{bmatrix}^{K - 1} \begin{bmatrix} 1 \\ 0 \end{bmatrix}$

#include <cstdio>

typedef long long LL;
const int Mod = 1000000007;
const int MN = 1005;

inline int qPow(int b, LL e) {
int a = 1;
for (; e; e >>= 1, b = (LL)b * b % Mod)
if (e & 1) a = (LL)a * b % Mod;
return a;
}

int N, M, A, B, C; LL K;
char S[MN][MN];
int R[2][2], Q[2][2], tmp[2][2];

int main() {
scanf("%d%d%lld", &N, &M, &K);
if (!K) return puts("1"), 0;
for (int i = 1; i <= N; ++i) {
scanf("%s", S[i] + 1);
for (int j = 1; j <= M; ++j)
if (S[i][j] == '#') ++A;
}
int ok1 = 0, ok2 = 0;
for (int i = 1; i <= N; ++i) if (S[i][1] == '#' && S[i][M] == '#') ++ok1;
for (int j = 1; j <= M; ++j) if (S[1][j] == '#' && S[N][j] == '#') ++ok2;
if (ok1 && ok2) return puts("1"), 0;
if (!ok1 && !ok2) return printf("%d\n", qPow(A, K - 1)), 0;
if (ok1) {
C = ok1;
for (int i = 1; i <= N; ++i)
for (int j = 1; j < M; ++j)
if (S[i][j] == '#' && S[i][j + 1] == '#') ++B;
} else {
C = ok2;
for (int j = 1; j <= M; ++j)
for (int i = 1; i < N; ++i)
if (S[i][j] == '#' && S[i + 1][j] == '#') ++B;
}
Q[0][0] = A, Q[1][0] = B, Q[1][1] = C;
R[0][0] = R[1][1] = 1;
#define F(i) for (int i = 0; i < 2; ++i)
--K;
while (K) {
if (K & 1) {
F(i) F(j) tmp[i][j] = 0;
F(i) F(j) F(k) tmp[i][k] = (tmp[i][k] + (LL)R[i][j] * Q[j][k]) % Mod;
F(i) F(j) R[i][j] = tmp[i][j];
}
F(i) F(j) tmp[i][j] = 0;
F(i) F(j) F(k) tmp[i][k] = (tmp[i][k] + (LL)Q[i][j] * Q[j][k]) % Mod;
F(i) F(j) Q[i][j] = tmp[i][j];
K >>= 1;
}
printf("%d\n", (R[0][0] - R[1][0] + Mod) % Mod);
return 0;
}

posted @ 2020-06-12 23:40  粉兔  阅读(32)  评论(0编辑  收藏