AtCoder Beginner Contest 164
A - Sheep and Wolves
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { int a, b; scanf("%d%d", &a, &b); printf("%s\n", a <= b ? "unsafe" : "safe"); return 0; }
B - Battle
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d); printf("%s\n", (c + b - 1) / b <= (a + d - 1) / d ? "Yes" : "No"); return 0; }
C - gacha
题意:给N个字符串S,求有多少个不同的字符串。
数据范围:$ 1 \leq N \leq 2 \times 10^{5} , 1 \leq |S| \leq 10$
题解:放set里计数即可。
#include <bits/stdc++.h> #define ll long long using namespace std; unordered_set<string> S; int main() { int n; cin >> n; for(int i = 0; i < n; i++) { string s; cin >> s; S.insert(s); } cout << S.size() << '\n'; return 0; }
D - Multiple of 2019
题意:给一个字符串S,求有多少个子串在十进制下对2019取模为0。
数据范围:$ 1 \leq |S| \leq2 \times 10^{5} $
题解:跟AtCoder Beginner Contest 158 E 差不多。
可以得知$10^{x} mod \ 2019 \neq 0$,那么对于$S[l...r]$子串,当且仅当$S[l...N] \equiv S[r...N] (mod\ 2019)$成立时,满足要求。
证明:$S[l...r] \times 10^{r-l} = S[l...N]-S[r...N] $,若$S[l...N]-S[r...N] \equiv 0(mod\ 2019)$,由于$10^{x} mod\ 2019 \neq 0$,可以得出$S[l...r]\ mod \ 2019 =0$,若 $S[l...r] \equiv 0(mod\ 2019)$,显然$S[l...r] \times 10^{r-l} \ mod \ 2019 = 0$
倒着遍历字符串,每次加上之前余数和当前余数相同的个数。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 2e5 + 5; char s[N]; int ma[2020]; int main() { scanf("%s", s); ll ans = 0; int res = 0, t = 1, n = strlen(s); for(int i = n - 1; i >= 0; i--) { ma[res]++; res = (res + (s[i] - '0') * t) % 2019; ans += ma[res]; t = t * 10 % 2019; } printf("%lld\n", ans); return 0; }
E - Two Currencies
题意:给N个城市,M条路,S个银币,每条路需要花费Ai个银币和Bi分钟,可以在第i个城市花费Di分钟获得Ci银币(无限次),求从1到2...n最少花费的时间。
数据范围:$ 2 \leq N \leq 50, N-1 \leq M \leq 100, 0 \leq S \leq 10^{9}, 1 \leq A_{i} \leq 50, 1 \leq B_{i},C_{i},D_{i} \leq 10^{9}$
题解:最短路,f[i][j]代表到第i个城市身上有j个银币的最少花费时间,由于A最大为50,那么身上只要有50*N的银币就可以到任意点。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N = 55; struct P{ int v, a, b; }; vector<P> G[N]; int c[N], d[N]; ll f[N][N * N]; int main() { int n, m, s; scanf("%d%d%d", &n, &m, &s), s = min(s, 2500); for(int i = 0, u, v, a, b; i < m; i++) { scanf("%d%d%d%d", &u, &v, &a, &b); G[u].push_back({v, a, b}); G[v].push_back({u, a, b}); } for(int i = 1; i <= n; i++) { scanf("%d%d", &c[i], &d[i]); } for(int i = 0; i < N; i++) { for(int j = 0; j < N * N; j++) { f[i][j] = 1e18; } } f[1][s] = 0; typedef tuple<ll, int, int> T; priority_queue<T, vector<T>, greater<T>> qu; qu.push(T(0, 1, s)); while(!qu.empty()) { ll t = get<0>(qu.top()); int u = get<1>(qu.top()), w = get<2>(qu.top()); qu.pop(); if(f[u][w] > t) continue; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i].v, a = G[u][i].a, b = G[u][i].b; if(w >= a && f[v][w - a] > t + b) { f[v][w - a] = t + b; qu.push(T(t + b, v, w - a)); } } if(f[u][min(w + c[u], 2500)] > t + d[u]) { f[u][min(w + c[u], 2500)] = t + d[u]; qu.push(T(t + d[u], u, min(w + c[u], 2500))); } } for(int i = 2; i <= n; i++) { ll ans = 1e18; for(int j = 0; j <= 2500; j++) { ans = min(ans, f[i][j]); } printf("%lld\n", ans); } return 0; }
F - I hate Matrix Construction
题意:构造一个N*N的矩阵,满足如果Si为0,第i行所有元素与运算后的值为Ui,反之,第i行所有元素或运算后的值为Ui。如果Ti为0,第i列所有元素与运算后的值为Vi,反之,第i列所有元素或运算后的值为Vi。
数据范围:$ 1 \leq N \leq 500, 0 \leq S_{i},T_{i} \leq 1, 0 \leq U_{i},V_{i} < 2^{64}$
题解:独立考虑每一个二进制位,把问题转化成构造64个N*N的01矩阵。
如果一行(一列)与运算以后为1,那么这一行(一列)全为1,如果一行(一列)或运算以后为0,那么这一行(一列)全为0。
对于每个没确定的元素,如果该元素的对应行列需要的值相同,就把该元素赋为这个值,反之就先赋为0。
剩下的就是一行(一列)或运算以后为1的情况,可以将每行每列的01个数计数,然后遍历判断当前位置能否将0变成1即可。
最后在整体判断一下是否满足要求。
#include <bits/stdc++.h> #define ll unsigned long long using namespace std; const int N = 505; int S[N], T[N], n; ll U[N], V[N], ans[N][N]; int t[N][N], R[N][2], C[N][2]; bool solve() { for(int k = 0; k < 64; k++) { memset(t, -1, sizeof t); memset(R, 0, sizeof R); memset(C, 0, sizeof C); for(int i = 1; i <= n; i++) { int x = (U[i] & 1); if(S[i] == x) continue; for(int j = 1; j <= n; j++) { if(~t[i][j] && t[i][j] != x) return false; t[i][j] = x; } } for(int i = 1; i <= n; i++) { int x = (V[i] & 1); if(T[i] == x) continue; for(int j = 1; j <= n; j++) { if(~t[j][i] && t[j][i] != x) return false; t[j][i] = x; } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if((U[i] & 1) == (V[j] & 1)) t[i][j] = (U[i] & 1); if(t[i][j] == -1) t[i][j] = 0; R[i][t[i][j]]++; C[j][t[i][j]]++; } } for(int i = 1; i <= n; i++) { if(S[i] && (U[i] & 1)) { if(R[i][1]) continue; for(int j = 1; j <= n; j++) { if(!T[j] && !(V[j] & 1) && C[j][0] > 1) { t[i][j] = 1; R[i][0]--, C[j][0]--; R[i][1]++, C[j][1]++; break; } } } } for(int i = 1; i <= n; i++) { if(T[i] && (V[i] & 1)) { if(C[i][1]) continue; for(int j = 1; j <= n; j++) { if(!S[j] && !(U[j] & 1) && R[j][0] > 1) { t[j][i] = 1; R[j][0]--, C[i][0]--; R[j][1]++, C[i][1]++; break; } } } } for(int i = 1; i <= n; i++) { if(S[i] == 0 && (U[i] & 1) == 1 && R[i][1] != n) return false; if(S[i] == 0 && (U[i] & 1) == 0 && R[i][1] == n) return false; if(S[i] == 1 && (U[i] & 1) == 1 && R[i][1] == 0) return false; if(S[i] == 1 && (U[i] & 1) == 0 && R[i][1] != 0) return false; if(T[i] == 0 && (V[i] & 1) == 1 && C[i][1] != n) return false; if(T[i] == 0 && (V[i] & 1) == 0 && C[i][1] == n) return false; if(T[i] == 1 && (V[i] & 1) == 1 && C[i][1] == 0) return false; if(T[i] == 1 && (V[i] & 1) == 0 && C[i][1] != 0) return false; } for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(t[i][j]) ans[i][j] |= (1ull << k); } } for(int i = 1; i <= n; i++) { U[i] >>= 1; V[i] >>= 1; } } return true; } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &S[i]); for(int i = 1; i <= n; i++) scanf("%d", &T[i]); for(int i = 1; i <= n; i++) scanf("%llu", &U[i]); for(int i = 1; i <= n; i++) scanf("%llu", &V[i]); if(!solve()) printf("-1\n"); else { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { printf("%llu%c", ans[i][j], j == n ? '\n' : ' '); } } } return 0; }