2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2) 题解
【题目链接】
最长公共子序列。保留最长公共子序列,剩余的删除或者补足即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; char s[maxn]; char t[maxn]; int dp[100][100]; int main() { scanf("%s", s); for(int i = 0; i < 26; i ++) { t[i] = i + 'a'; t[i + 1] = 0; } int lens = strlen(s); int lent = strlen(t); for(int i = 1; i <= lens; i ++) { for(int j = 1; j <= lent; j ++) { if(s[i - 1] == t[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } printf("%d\n", 26 - dp[lens][lent]); return 0; }
暴力。枚举哪几个一定用,去剩余的那些里面枚举是否可以凑出和这几个一样的。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int n, m; long long a[maxn], b[maxn]; long long ans[maxn]; long long p[maxn]; long long sum[maxn]; int sz, cnt; long long B[maxn]; long long sumB[maxn]; int lowbit(int x) { return x & (-x); } int main() { cin >> n >> m; for(int i = 0; i < n; i ++) cin >> a[i]; for(int i = 0; i < m; i ++) cin >> b[i]; for(int i = 1; i < (1 << m); i ++) { for(int j = 0; j < m; j ++) { if((1 << j) & i) sum[i] += b[j]; } } for(int i = 0; i < (1 << m); i ++) { sz = 0; for(int j = 0; j < m; j ++) { if((1 << j) & i) continue; B[sz ++] = b[j]; } // sum[i]; if(sum[i] == 0) { p[cnt ++] = sum[i]; continue; } sumB[0] = 0; for(int j = 0; j < sz; j ++) { sumB[1 << j] = B[j]; } for(int j = 1; j < (1 << sz); j ++) { sumB[j] = sumB[j - lowbit(j)] + sumB[lowbit(j)]; if(sumB[j] == sum[i]) { p[cnt ++] = sum[i]; break; } } } sz = 0; for(int i = 0; i < cnt; i ++) { for(int t = 0; t < n; t ++) { ans[sz ++] = p[i] * 2 + a[t]; } } sort(ans, ans + sz); for(int i = 0; i < sz; i ++) { if(i >= 1 && ans[i] == ans[i - 1]) continue; printf("%lld\n", ans[i]); } return 0; } /* 2 5 100 110 5 5 1 4 6 */
记$f[i][x][y]$表示操作了前$i$个指令,当前在$(x,y)$位置的最小费用。分析可以发现是一个边权只有$0$和$1$的最短路问题。
#include<bits/stdc++.h> using namespace std; const int maxn = 60; int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1}, }; int n, m; char s[maxn][maxn]; char op[maxn]; int len; int dp[maxn][maxn][maxn]; int f[maxn][maxn][maxn]; int sx, sy, ex, ey; int out(int x, int y) { if(x < 0 || x >= n) return 1; if(y < 0 || y >= m) return 1; return 0; } int Hash(int a, int x, int y) { return a * 10000 + x * 100 + y; } void Get(int st, int &a, int &x, int &y) { y = st % 100; st = st / 100; x = st % 100; st = st / 100; a = st; } void work() { queue<int> q; dp[0][sx][sy] = 0; f[0][sx][sy] = 1; q.push(Hash(0, sx, sy)); while(!q.empty()) { int st = q.front(); q.pop(); int a, x, y; Get(st, a, x, y); f[a][x][y] = 0; /* insert */ for(int i = 0; i < 4; i ++) { int tx = x + dir[i][0]; int ty = y + dir[i][1]; if(out(tx, ty)) continue; if(s[tx][ty] == '#') continue; if(dp[a][tx][ty] > dp[a][x][y] + 1) { dp[a][tx][ty] = dp[a][x][y] + 1; if(f[a][tx][ty] == 0) { f[a][tx][ty] = 1; q.push(Hash(a, tx, ty)); } } } /* del */ if(a < len) { if(dp[a + 1][x][y] > dp[a][x][y] + 1) { dp[a + 1][x][y] = dp[a][x][y] + 1; if(f[a + 1][x][y] == 0) { f[a + 1][x][y] = 1; q.push(Hash(a + 1, x, y)); } } } /* use */ if(a < len) { int d; if(op[a] == 'U') d = 0; if(op[a] == 'R') d = 1; if(op[a] == 'D') d = 2; if(op[a] == 'L') d = 3; int tx = x + dir[d][0]; int ty = y + dir[d][1]; if(out(tx, ty) || s[tx][ty] == '#') { tx = x; ty = y; } if(dp[a + 1][tx][ty] > dp[a][x][y]) { dp[a + 1][tx][ty] = dp[a][x][y]; if(f[a + 1][tx][ty] == 0) { f[a + 1][tx][ty] = 1; q.push(Hash(a + 1, tx, ty)); } } } } } int main() { scanf("%d%d", &n, &m); for(int i = 0; i < n; i ++) { scanf("%s", s[i]); } scanf("%s", op); len = strlen(op); for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(s[i][j] == 'R') sx = i, sy = j; if(s[i][j] == 'E') ex = i, ey = j; for(int k = 0; k <= len; k ++) { dp[k][i][j] = 100000; } } } work(); int ans = 100000; for(int i = 0; i <= len; i ++) { ans = min(ans, dp[i][ex][ey]); } printf("%d\n", ans); return 0; } /* 3 3 R.. .#. ..E LRDD 2 4 R.#. #..E RRUUDDRRUUUU */
贪心。每一个区间看,贪心靠后放$1$即可。
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int f[maxn]; int n, k, r; int main() { scanf("%d%d%d", &n, &k, &r); for(int i = 1; i <= k; i ++) { int x; scanf("%d", &x); f[x] = 1; } int ans = 0; int sum = 0; for(int i = 1; i <= r; i ++) { sum += f[i]; } int R = r; while(sum < 2) { if(f[R]) R --; else { sum ++; f[R] = 1; ans ++; R --; } } for(int i = r + 1; i <= n; i ++) { sum -= f[i - r]; sum += f[i]; int L = i - r + 1; int R = i; while(sum < 2) { if(f[R]) R --; else { sum ++; f[R] = 1; ans ++; R --; } } } printf("%d\n", ans); return 0; }
优先队列。
#include <bits/stdc++.h> using namespace std; int n, k; long long a[500]; priority_queue<long long> p; int main() { scanf("%d%d", &n, &k); for(int i = 1; i <= n; i ++) { cin >> a[i]; } long long ans = 0; long long time = 0; for(int i = 1; i <= k; i ++) { p.push(-a[i]); } for(int i = k + 1; i <= n; i ++) { long long u = -p.top(); p.pop(); time += u; ans += time; p.push(-a[i]); } while(!p.empty()) { long long u = -p.top(); p.pop(); time += u; ans += time; } cout << ans << endl; return 0; }
水题。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; char s[maxn]; int main() { int a, b, c; cin >> a; cin >> s; cin >> b; cin >> s; cin >> c; if(a + b == c) puts("YES"); else puts("NO"); return 0; }
模拟。
#include <bits/stdc++.h> using namespace std; const int maxn = 1000; char s[maxn][maxn]; int main() { int n, m; scanf("%d%d", &n, &m); for(int i = 0; i < n; i ++) { scanf("%s", s[i]); } for(int i = n - 2; i >= 0; i --) { for(int j = 0; j < m; j ++) { if(s[i][j] != 'o') continue; int x = i; for(int k = i + 1; k < n; k ++) { if(s[k][j] == '.') x = k; else break; } s[i][j] = '.'; s[x][j] = 'o'; } } for(int i = 0; i < n; i ++) { printf("%s\n", s[i]); } return 0; } /* 3 3 ooo #.. ..# 4 2 oo oo o. .. */
从每一个未被遍历过的$L$开始遍历,$C$当做$L$。
#include <bits/stdc++.h> using namespace std; const int maxn = 1010; char s[maxn][maxn]; int n, m; int ans; int f[maxn][maxn]; int dir[4][2] = { {0, -1}, {0, 1}, {1, 0}, {-1, 0}, }; int out(int x, int y) { if(x < 0 || x >= n) return 1; if(y < 0 || y >= m) return 1; return 0; } void dfs(int x, int y) { f[x][y] = 1; for(int i = 0; i < 4; i ++) { int tx = x + dir[i][0]; int ty = y + dir[i][1]; if(out(tx, ty)) continue; if(s[tx][ty] == 'W') continue; if(f[tx][ty]) continue; dfs(tx, ty); } } int main() { scanf("%d%d", &n, &m); for(int i = 0; i < n; i ++) { scanf("%s", s[i]); } for(int i = 0; i < n; i ++) { for(int j = 0; j < m; j ++) { if(f[i][j]) continue; if(s[i][j] == 'L') { dfs(i, j); ans ++; } } } cout << ans << endl; return 0; } /* 4 5 CCCCC CCCCC CCCCC CCCCC 3 2 LW CC WL */
二分。和这里的F题一样的做法,不再赘述。
#include <bits/stdc++.h> using namespace std; int T, n, k; const int maxn = 1e5 + 10; long long a[maxn]; int check(long long x) { long long p = 0; for(int i = 1; i <= n; i ++) { p = p + min(x, a[i]); } if(p >= x * k) return 1; return 0; } int main() { scanf("%d", &n); k = 2; for(int i = 1; i <= n; i ++) { scanf("%lld", &a[i]); } long long L = 0; long long R = 1e12; long long ans = 0; while(L <= R) { long long mid = (L + R) / 2; if(check(mid)) ans = mid, L = mid + 1; else R = mid - 1; } printf("%lld\n", ans); return 0; }
贪心。原点左侧和右侧分开计算。每一侧计算的时候由远及近进行操作即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; struct X { long long x; long long m; }s[maxn]; int n; long long k; bool cmp(const X& a, const X& b) { return a.x < b.x; } int main() { scanf("%d%lld", &n, &k); for(int i = 1; i <= n; i ++) { scanf("%lld%lld", &s[i].x, &s[i].m); } sort(s + 1, s + 1 + n, cmp); long long ans = 0; int p; if(s[1].x <= 0) { for(int i = 1; i <= n; i ++) { if(s[i].x <= 0) p = i; } while(1) { int now = -1; for(int i = 1; i <= p; i ++) { if(s[i].m) { now = i; break; } } if(now == -1) break; if(s[now].m >= k) { long long ci = s[now].m / k; ans = ans - ci * s[now].x; s[now].m = s[now].m % k; } else { long long tmp = k; ans = ans - s[now].x; while(tmp) { if(now > p) break; long long A = min(tmp, s[now].m); tmp = tmp - A; s[now].m -= A; now ++; } } } } p = -1; for(int i = 1; i <= n; i ++) { if(s[i].x > 0) { p = i; break; } } if(p != -1) { while(1) { int now = -1; for(int i = p; i <= n; i ++) { if(s[i].m) { now = i; } } if(now == -1) break; if(s[now].m >= k) { long long ci = s[now].m / k; ans = ans + ci * s[now].x; s[now].m = s[now].m % k; } else { long long tmp = k; ans = ans + s[now].x; while(tmp) { if(now < p) break; long long A = min(tmp, s[now].m); tmp = tmp - A; s[now].m -= A; now --; } } } } cout << ans * 2LL << endl; return 0; } /* 4 10 -7 5 -2 3 5 7 9 5 7 1 9400000 10000000 9500000 10000000 9600000 10000000 9700000 10000000 9800000 10000000 9900000 10000000 10000000 10000000 */
模拟。操作的次数越多,答案精度越高。
#include <bits/stdc++.h> using namespace std; const int maxn = 1000; int a[maxn], b[maxn]; int main() { double ping = 0; double win = 0; for(int i = 1; i <= 6; i ++) cin >> a[i]; for(int i = 1; i <= 6; i ++) cin >> b[i]; for(int i = 1; i <= 6; i ++) { for(int j = 1; j <= 6; j ++) { if(a[i] == b[j]) ping ++; if(a[i] > b[j]) win ++; } } ping /= 36.0; win /= 36.0; double ans = 0.0; double x = 1.0; for(int i = 1; i <= 1000000; i ++) { ans = ans + x * win; x = x * ping; } printf("%.5f\n", ans); return 0; }
暴力枚举所有情况。
#include <bits/stdc++.h> using namespace std; const int maxn = 5e5 + 10; int n, m; int a[maxn], b[maxn]; int t[maxn]; int A[maxn], B[maxn]; int main() { cin >> a[0] >> b[0]; cin >> a[1] >> b[1]; cin >> a[2] >> b[2]; t[0] = 0, t[1] = 1, t[2] = 2; int ok = 0; do { // printf("%d %d %d\n", t[0], t[1], t[2]); for(int i = 0; i < 8; i ++) { for(int j = 0; j < 3; j ++) { if((i << j) & i) { B[j] = a[t[j]]; A[j] = b[t[j]]; } else { A[j] = a[t[j]]; B[j] = b[t[j]]; } } // 1 if(A[0] == A[1] && A[0] == A[2] && B[0] + B[1] + B[2] == A[0]) ok = 1; // 2 if(B[0] == B[1] && B[0] == B[2] && A[0] + A[1] + A[2] == B[0]) ok = 1; // 3 if(B[1] + B[2] == B[0] && A[1] == A[2] && A[1] + A[0] == B[0]) ok = 1; // 5 if(B[1] == B[2] && A[1] + A[2] == A[0] && A[0] == B[0] + B[1]) ok = 1; } } while(next_permutation(t, t + 3)); if(ok) puts("YES"); else puts("NO"); return 0; }
记录以每个位置为结尾的且在波峰以及波谷的最长序列长度,和LIS一样转移即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 2000000; int n; int d[maxn]; int dp[maxn][2]; int main() { cin >> n; for(int i = 1; i <= n; i ++) { cin >> d[i]; } int ans = 0; for(int i = 1; i <= n; i ++) { int mx = 0; // dp[i][0]; for(int j = 1; j < i; j ++) { if(d[j] > d[i]) mx = max(mx, dp[j][1]); } dp[i][0] = mx + 1; ans = max(ans, dp[i][0]); mx = 0; // dp[i][1]; for(int j = 1; j < i; j ++) { if(d[j] < d[i]) mx = max(mx, dp[j][0]); } dp[i][1] = mx + 1; ans = max(ans, dp[i][1]); } cout << ans << endl; return 0; }