Atcoder Grand Contest 003 题解
A - Wanna go back home
如果有S就必须要有N,反之亦然,如果有E必须要有W,反之亦然。判断一下就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int n; char str[2333]; bool t[4]; int main() { scanf("%s", str + 1); n = strlen(str + 1); for (int i = 1; i <= n; ++i) { if (str[i] == 'W') t[0] = 1; if (str[i] == 'E') t[1] = 1; if (str[i] == 'N') t[2] = 1; if (str[i] == 'S') t[3] = 1; } puts(t[0] == t[1] && t[2] == t[3] ? "Yes" : "No"); }
B - Simplified mahjong
先O(n)扫一遍,把奇数的能删就删去一个。最后每个除以二再求和就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int n, a[100010]; long long ans; int main() { gi(n); for (int i = 1; i <= n; ++i) gi(a[i]); for (int i = 1; i <= n; ++i) { if (a[i] & 1) { if (a[i + 1]) ++ans, --a[i], --a[i + 1]; } } for (int i = 1; i <= n; ++i) { ans += a[i] >> 1; } printf("%lld\n", ans); return 0; }
C - BBuBBBlesort!
我们发现操作2使得奇数偶数独立,我们只要算应该在奇数位置最后到偶数位置的数有多少个就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int n; PII a[100010]; int main() { gi(n); for (int i = 1; i <= n; ++i) gi(a[i].fi), a[i].se = i; sort(a + 1, a + n + 1); int ans = 0; for (int i = 1; i <= n; ++i) if ((a[i].se & 1) != (i & 1)) ++ans; printf("%d\n", ans >> 1); return 0; }
D - Anticube
首先因子里有立方的可以直接除掉,不会有影响,那么一个数对应的就是唯一的,筛法找出那个数字,算一下就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } int n; long long s[100010]; map<long long, int> h, t; int p[3010], fg[3010], pt; int main() { gi(n); for (int i = 1; i <= n; ++i) scanf("%lld", s + i); for (int i = 2; i <= 3000; fg[i] ? : p[++pt] = i, ++i) for (int j = i << 1; j <= 3000; j += i) fg[j] = 1; long long mx = 0; for (int i = 1; i <= n; ++i) { for (int j = 1; 1LL * p[j] * p[j] * p[j] <= s[i]; ++j) { long long t = 1LL * p[j] * p[j] * p[j]; while (!(s[i] % t)) s[i] /= t; } ++h[s[i]]; mx = max(mx, s[i]); //cerr << "s = " << s[i] << endl; } int ans = 0; t = h; for (auto iter : t) { long long x = iter.first; if (x == 1) continue; long long y = 1; for (int j = 1; j <= pt; ++j) { int cnt = 0; while (!(x % p[j])) x /= p[j], ++cnt; if (cnt == 1) y *= p[j] * p[j]; else if (cnt == 2) y *= p[j]; } if (x != 1) { long long s = sqrt(x); if (x == s * s) y *= s; else y *= x * x; } //cerr << iter.first << ", " << y << ", " << x << endl; if(!h.count(y) || iter.first < y) ans += max(iter.second, h.count(y) ? h[y] : 0); } if (h[1]) ++ans; printf("%d\n", ans); return 0; }
E - Sequential operations on Sequence
倒着模拟,首先qi变成单调上升的,就可以二分了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } const int N = 1e5 + 10; int n, Q, m; long long q[N], t[N], s[N]; int find(long long k, int n) { int t = 0; for (int i = 19; ~i; --i) { if (t + (1 << i) > n) continue; if (q[t + (1 << i)] <= k) t += 1 << i; } return t; } int main() { gii(n, Q); q[++m] = n; for (int i = 1; i <= Q; ++i) { long long x; scanf("%lld", &x); while (x <= q[m]) --m; q[++m] = x; } t[m] = 1; for (int i = m; i; --i) { long long k = q[i]; int p = find(k, i - 1); while (p) { t[p] += (k / q[p]) * t[i]; k %= q[p]; p = find(k, p - 1); } s[1] += t[i], s[k + 1] -= t[i]; } long long ans = 0; for (int i = 1; i <= n; ++i) ans += s[i], printf("%lld\n", ans); return 0; }
F - Fraction of Fractal
首先考虑行有连接列也有连接的,那么连通块个数肯定为1,都没有连接就是黑格子个数的K-1次方,只有一边连接,假设是行,从K拓展到K+1的时候,公式:K+1层的连通块个数=K层的黑格子个数-K层的左右格子对,因为上下不会扩展,所以只要减去左右,那么我们就要维护黑格子个数和左右相连的格子有多少个,还要再维护边界有多少相邻,才能转移。
x' = x^2(黑格子个数)
y' = z * y + x * y(左右相连格子个数)
z' = z * z(边界相邻格子数)
矩阵乘法计算就好了。
//waz #include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back #define fi first #define se second #define ALL(x) (x).begin(), (x).end() #define SZ(x) ((int)((x).size())) typedef pair<int, int> PII; typedef vector<int> VI; typedef long long int64; typedef unsigned int uint; typedef unsigned long long uint64; #define gi(x) ((x) = F()) #define gii(x, y) (gi(x), gi(y)) #define giii(x, y, z) (gii(x, y), gi(z)) int F() { char ch; int x, a; while (ch = getchar(), (ch < '0' || ch > '9') && ch != '-'); if (ch == '-') ch = getchar(), a = -1; else a = 1; x = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - '0'; return a * x; } const int mod = 1e9 + 7; struct matrix { int a[2][2]; matrix operator * (matrix that) { matrix ans; memset(ans.a, 0, sizeof ans.a); for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) for (int k = 0; k < 2; ++k) ans.a[i][j] = (ans.a[i][j] + 1LL * a[i][k] * that.a[k][j]) % mod; return ans; } } w; int fpow(int a, long long x) { int ret = 1; for (; x; x >>= 1) { if (x & 1) ret = 1LL * ret * a % mod; a = 1LL * a * a % mod; } return ret; } matrix fpow(matrix a, long long x) { matrix ret; memset(ret.a, 0, sizeof ret.a); ret.a[0][0] = ret.a[1][1] = 1; for (; x; x >>= 1) { if (x & 1) ret = ret * a; a = a * a; } return ret; } int H, W; long long K; char str[1010][1010]; int main() { scanf("%d%d%lld", &H, &W, &K); for (int i = 1; i <= H; ++i) scanf("%s", str[i] + 1); int cntH = 0, cntW = 0; for (int i = 1; i <= H; ++i) if (str[i][1] == str[i][W] && str[i][1] == '#') ++cntH; for (int i = 1; i <= W; ++i) if (str[1][i] == str[H][i] && str[1][i] == '#') ++cntW; int cnt = 0; for (int i = 1; i <= H; ++i) for (int j = 1; j <= W; ++j) if (str[i][j] == '#') ++cnt; if (!cntH && !cntW) { printf("%d\n", fpow(cnt, K - 1)); return 0; } if ((cntH && cntW) || !K) { puts("1"); return 0; } if (cntH) { w.a[0][0] = cnt; for (int i = 1; i <= H; ++i) for (int j = 1; j < W; ++j) if (str[i][j] == '#' && str[i][j + 1] == '#') ++w.a[0][1]; w.a[1][1] = cntH; } else { w.a[0][0] = cnt; for (int i = 1; i < H; ++i) for (int j = 1; j <= W; ++j) if (str[i][j] == '#' && str[i + 1][j] == '#') ++w.a[0][1]; w.a[1][1] = cntW; } w = fpow(w, K - 1); printf("%d\n", (w.a[0][0] - w.a[0][1] + mod) % mod); return 0; }