最近比較忙,題解寫的有點水ios
題意:給定 \(n\) 條直線,兩條相互垂直的直線交點處要修建一個十字路口,詢問須要修建幾個十字路口。c++
分析:這題題意至關坑,並非求相互垂直的直線的不一樣交點數量,而是不一樣的「十字路口數量」,這有什麼區別呢?參考下圖:算法
左邊雖然有兩對相互垂直的直線,但只要建一個「十字路口」,但右邊須要建兩個。ui
看明白題意以後這題就不難了,跟 CCPC2019 秦皇島站 A. Angle Beats 的作法是同樣的,把全部直線用最簡形式的向量存儲,刪除共線後計數便可。this
#include <bits/stdc++.h> #define mp make_pair #define ll long long using namespace std; void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); } int __gcd(int a, int b) { return b == 0 ? a : __gcd(b, a % b); } int main() { io(); int t; cin >> t; while (t--) { int n; cin >> n; vector<pair<pair<int, int>, int> > p; map<pair<int, int>, int> MP; for (int i = 1; i <= n; ++i) { int xa, ya, xb, yb; cin >> xa >> ya >> xb >> yb; int x = xb - xa, y = yb - ya; int g = __gcd(x, y); x /= g, y /= g; if (y < 0) x = -x, y = -y; else if (y == 0) x = abs(x); p.emplace_back(mp(mp(x, y), xa * y - ya * x)); } sort(p.begin(), p.end()); p.erase(unique(p.begin(), p.end()), p.end()); for (auto it : p) MP[it.first]++; ll ans = 0; for (auto it : p) { int x = it.first.second, y = -it.first.first; if (y < 0) x = -x, y = -y; else if (y == 0) x = abs(x); ans += MP[mp(x, y)]; } cout << ans / 2ll << '\n'; } }
題意:略。spa
分析:水題。code
#include <bits/stdc++.h> #define ll long long using namespace std; void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); } int main() { io(); string x, y; cin >> x; y = x; reverse(y.begin(), y.end()); for (int i = 0; i <= x.length(); ++i) { string p = y.substr(y.size() - i, i); string tmp = x + p; string tp = tmp; reverse(tp.begin(), tp.end()); if (tp == tmp) { cout << tmp; return 0; } } }
題意:給定兩個由 \(A,C,G,T\) 構成的長度爲 \(n\) 的字符串,求出他們的最長公共子序列,而後判斷這個子序列的長度和 \(0.99n\) 的大小關係。orm
分析:\(dp\) ,隊友秒了。blog
#include<bits/stdc++.h> #define ll long long #define maxn 100100 #define mod 998244353 using namespace std; int dp[1010][1010]; char s1[maxn], s2[maxn]; int main() { scanf("%s%s", s1, s2); int n = strlen(s1); int m = n / 100 + 1; int ans = 0; for (int i = 0; i <= m; i++) { for (int j = 0; j <= m; j++) { while (i + dp[i][j] < n && j + dp[i][j] < n && s1[i + dp[i][j]] == s2[j + dp[i][j]]) dp[i][j]++; dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]); dp[i][j + 1] = max(dp[i][j + 1], dp[i][j]); ans = max(ans, dp[i][j]); } } if (ans * 100 >= n * 99) printf("Long lost brothers D:\n"); else printf("Not brothers :(\n"); return 0; }
題意:給定一個字符串 \(s\) ,\(q\) 次修改,每次將 \(i+ak\) 這些位置的字母修改,詢問修改完後的字符串。ci
分析:數據水,暴力剪枝假算法過了。
#define _CRT_SECURE_NO_WARNINGS #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #pragma comment(linker, "/stack:200000000") #include <bits/stdc++.h> #define mp make_pair #define SIZE 100010 #define ll long long using namespace std; void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); } vector<pair<int, char> > in[SIZE]; vector<pair<int, char> > out[SIZE]; int main() { io(); string s; cin >> s; s = " " + s; int q; cin >> q; vector<int> lazy(s.length(), 0); for (int i = 1; i <= q; ++i) { int p, a, k; char c; cin >> p >> a >> k >> c; if (a == 1) { in[p].emplace_back(mp(i, c)); out[p + k + 1].emplace_back(mp(i, c)); } else { for (int j = 0; j <= k; ++j) { s[p + a * j] = c; lazy[p + a * j] = i; } } } set<pair<int, char> > st; for (int i = 1; i < s.length(); ++i) { for (auto it : in[i]) if (!st.count(it)) st.insert(it); for (auto it : out[i]) if (st.count(it)) st.erase(it); if (st.size()) { if (st.rbegin()->first > lazy[i]) cout << st.rbegin()->second; else cout << s[i]; } else cout << s[i]; } }
題意:求一個扇形(剪掉一個小扇形)區域內最多能覆蓋多少點。
分析:\(POJ2482\) 翻版,從水平掃描線變成旋轉掃描線,不過仍是一個標準的掃描線+線段樹裸題。
#include<bits/stdc++.h> #define ll long long #define maxn 100100 #define mod 998244353 #define eps 1e-8 using namespace std; struct cv { int x, y; }a[maxn * 2]; bool cmp(cv p, cv q) { return p.y < q.y; } int tr[maxn * 4], lz[maxn * 4]; void up(int x) { tr[x] = max(tr[x * 2], tr[x * 2 + 1]); } void pe(int x) { if (lz[x]) { tr[x * 2] += lz[x]; tr[x * 2 + 1] += lz[x]; lz[x * 2] += lz[x]; lz[x * 2 + 1] += lz[x]; lz[x] = 0; } } void cg(int x, int l, int r, int s, int e, int y) { if (l >= s && r <= e) { tr[x] += y; lz[x] += y; return; } pe(x); int mid = (l + r) / 2; if (mid >= s) cg(x * 2, l, mid, s, e, y); if (mid < e) cg(x * 2 + 1, mid + 1, r, s, e, y); up(x); } int main() { int n, d, w; double wi; scanf("%d%d%lf", &n, &d, &wi); w = (int)(wi * 100 + eps); for (int i = 0; i < n; i++) { scanf("%d%lf", &a[i].x, &wi); a[i].y = (int)(wi * 100 + eps); } sort(a, a + n, cmp); for (int i = 0; i < n; i++) { a[i + n] = a[i]; a[i + n].y += 36000; } n *= 2; int l = 0, r = 0, ans = 0; memset(tr, 0, sizeof(tr)); memset(lz, 0, sizeof(lz)); while (r < n) { int cnt = 0; for (int i = r; i < n; i++) { if (a[i].y == a[r].y) { cg(1, 0, 100000, max(0, a[i].x - d), a[i].x, 1); cnt++; } else break; } while (l < r) { if (a[r].y - a[l].y > w) { cg(1, 0, 100000, max(0, a[l].x - d), a[l].x, -1); l++; } else break; } r += cnt; ans = max(ans, tr[1]); } printf("%d\n", ans); return 0; }
題意:給出一個式子,求結果。
分析:分數類大模擬,注意一定爆 \(int\) ,若是運算順序很差還會爆 \(long\ long\) 。
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define int LL const int maxn = 2e5 + 5; char s[maxn]; struct Fac { int x; int y; Fac() {} Fac(int x, int y) : x(x), y(y) {} void change() { x *= -1; } void trans() { if (!y) return; if (!x) { y = 1; return; } int gcd = __gcd(x, y); x /= gcd; y /= gcd; if (y < 0) { y *= -1; x *= -1; } } Fac friend operator+(const Fac& a, const Fac& b) { int lcm = a.y / __gcd(a.y, b.y) * b.y; int x1 = a.x * (lcm / a.y), x2 = b.x * (lcm / b.y); Fac res(x1 + x2, lcm); res.trans(); return res; } void print() { cout << x << "/" << y << '\n'; } }; vector<Fac> res; vector<int> fres; signed main() { while (~scanf("%s", s + 1)) { res.clear(); int g = 1; fres.clear(); fres.push_back(1); int len = strlen(s + 1); int f = g; for (int i = 1; i <= len; i++) { if (s[i] == '-') f *= -1; else if (s[i] == '+') f *= 1; else if (s[i] >= '0' && s[i] <= '9') { int x = 0, y = 0, ff = 1; while (s[i] != '/') x = x * 10 + s[i] - '0', i++; i++; if (s[i] == '-') ff *= -1, i++; while (s[i] >= '0' && s[i] <= '9') y = y * 10 + s[i] - '0', i++; i--; Fac a = Fac(x, y); a.trans(); if (f * ff == -1) a.change(); f = g; if (res.empty()) res.push_back(a); else res.back() = res.back() + a; } else if (s[i] == '(') { fres.push_back(f); g = fres.back(); f = g; } else if (s[i] == ')') { fres.pop_back(); g = fres.back(); f = g; } } res.back().trans(); res.back().print(); } return 0; }
我也不知道是啥,隊友秒了。
#include<bits/stdc++.h> #define ll long long #define maxn 10010 #define mod 998244353 using namespace std; vector<int>b[maxn]; int ans[maxn]; void sol(int x, int d) { ans[d]++; for (int i = 0; i < b[x].size(); i++) { sol(b[x][i], d + 1); } } int main() { int n, k; scanf("%d%d", &n, &k); for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); b[x].push_back(i); } sol(0, 0); int r = maxn - 1; while (!ans[r]) r--; int sum = 0, num = 0; for (int i = r; i > 0; i--) { sum += ans[i]; num++; while (num * k < sum) num++; } printf("%d\n", num); return 0; }
題意:略。
分析:折半搜索。
#define _CRT_SECURE_NO_WARNINGS #pragma GCC optimize(3) #pragma GCC optimize("Ofast") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #pragma comment(linker, "/stack:200000000") #include <bits/stdc++.h> #define SIZE 5000100 #define ll long long using namespace std; void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); } const ll mod = 1e15 + 37; vector<string> s(3); ll a[SIZE], b[SIZE], p[30]; int pa, pb, n, m; void dfs(int pos, ll sum, ll a[], int& cnt, int m) { if (pos == m) { a[cnt++] = sum; return; } for (int i = 0; i < 3; ++i) { ll tmp = (sum + 1ll * s[i][pos] * p[n - 1 - pos] % mod) % mod; dfs(pos + 1, tmp, a, cnt, m); } } ll solve() { for (int i = 0; i < 3; ++i) cin >> s[i]; n = s[0].length(); pa = pb = 0; m = n >> 1; dfs(0, 0, a, pa, m); dfs(m, 0, b, pb, n); sort(a, a + pa); sort(b, b + pb); a[pa] = a[0] + mod; b[pb] = b[0] + mod; int pos = pa; ll ans = mod; for (int i = 0; i < pb; ++i) { while (pos > 0 && b[i] + a[pos - 1] >= mod) --pos; ans = min(ans, a[pos] + b[i] - mod); } return ans; } int main() { io(); p[0] = 1; for (int i = 1; i < 30; ++i) p[i] = p[i - 1] * 127ll % mod; int x; cin >> x >> x; ll A = solve(); ll B = solve(); if (A < B) cout << "Owls"; else if (A > B) cout << "Goats"; else cout << "Tie"; }
題意:找最長的前綴數字。
分析:簽到。
#include <bits/stdc++.h> #define ll long long using namespace std; void io() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); } int main() { io(); string s; cin >> s; bool f = false; for (auto i : s) { if (i >= '0' && i <= '9') { f = true; cout << i; } else break; } if (!f) cout << "-1"; }
隊友說是簡單的線段樹。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; typedef long long LL; int a[maxn]; namespace Segement { const LL inf = 0X3f3f3f3f3f3f3f3f; LL tree[maxn << 2], vis[maxn << 2], h[maxn << 2]; LL lazy[maxn << 2]; void build(int root, int left, int right) { if (left == right) { vis[root] = 1; h[root] = tree[root] = a[left]; return; } int mid = (left + right) >> 1; build(root << 1, left, mid); build(root << 1 | 1, mid + 1, right); h[root] = min(h[root << 1], h[root << 1 | 1]); vis[root] = vis[root << 1] + vis[root << 1 | 1]; tree[root] = tree[root << 1] + tree[root << 1 | 1]; } void pushdown(int root) { if (!lazy[root]) return; h[root << 1] -= lazy[root]; h[root << 1 | 1] -= lazy[root]; tree[root << 1] -= vis[root << 1] * lazy[root]; tree[root << 1 | 1] -= vis[root << 1 | 1] * lazy[root]; lazy[root << 1] += lazy[root]; lazy[root << 1 | 1] += lazy[root]; lazy[root] = 0; } void update(int root, int left, int right, int stdl, int stdr, LL val) { if (left >= stdl && right <= stdr && val <= h[root]) { h[root] -= val; tree[root] -= vis[root] * val; lazy[root] += val; return; } if (left == right && h[root] < val) { tree[root] = vis[root] = 0; h[root] = inf; return; } pushdown(root); int mid = (left + right) >> 1; if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val); if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val); h[root] = min(h[root << 1], h[root << 1 | 1]); vis[root] = vis[root << 1] + vis[root << 1 | 1]; tree[root] = tree[root << 1] + tree[root << 1 | 1]; } LL query(int root, int left, int right, int stdl, int stdr) { if (left >= stdl && right <= stdr) { return tree[root]; } pushdown(root); LL res = 0; int mid = (left + right) >> 1; if (stdl <= mid) res += query(root << 1, left, mid, stdl, stdr); if (stdr > mid) res += query(root << 1 | 1, mid + 1, right, stdl, stdr); return res; } } int main() { int n, q; scanf("%d%d", &n, &q); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); Segement::build(1, 1, n); int p, a, b, w; while (q--) { scanf("%d", &p); if (p == 1) { scanf("%d%d", &a, &b); LL ans; if (a <= b) ans = Segement::query(1, 1, n, a, b); else ans = Segement::query(1, 1, n, a, n) + Segement::query(1, 1, n, 1, b); printf("%lld\n", ans); } else { scanf("%d%d%d", &a, &b, &w); if (a <= b) Segement::update(1, 1, n, a, b, w); else Segement::update(1, 1, n, a, n, w), Segement::update(1, 1, n, 1, b, w); } } return 0; }
隊友說是簽到。
#include <bits/stdc++.h> using namespace std; int main() { int t; scanf("%d", &t); while (t--) { int n; scanf("%d", &n); int ans = n / 3; if (ans) ans = (ans - 1) * 2 + 1; if (n / 3 && n % 3) ans++; if (n >= 3) ans++; printf("%d\n", ans); } return 0; }
題意:交互題,給定一堆試管,每次可以用這些試管加入試劑,加多了會變紅,少了會變綠,正好會變黃,詢問應該加多少試劑,或者判斷不能求出應該加入多少試劑。
分析:用揹包把全部能夠表示的求出來,而後二分。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5; bool dp[maxn]; int pre[maxn], p[maxn]; int n, a[105], vis[105]; int cnt[maxn]; void check(int mid) { int now = cnt[mid]; memset(vis, 0, sizeof(vis)); while (now) { vis[p[now - pre[now]]]++; now = pre[now]; } printf("1\n"); for (int i = 1; i <= n; i++) printf("%d ", vis[i]); printf("\n"); fflush(stdout); } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); int limit = 1e6; dp[0] = true; for (int i = 1; i <= n; i++) { for (int j = 0; j <= limit - a[i]; j++) if (dp[j]) dp[j + a[i]] = true, pre[j + a[i]] = j; } int k = 0; for (int i = 1; i <= limit; i++) if (dp[i]) cnt[++k] = i; for (int i = 1; i <= n; i++) p[a[i]] = i; char s[20]; int left = 1, right = k, mid, ans = -1; while (left <= right) { mid = (left + right) >> 1; check(mid); scanf("%s", s + 1); if (s[1] == 'y') { ans = cnt[mid]; break; } else if (s[1] == 'g') left = mid + 1; else right = mid - 1; } if (ans == -1) { if (cnt[mid] == 2 && s[1] == 'r') ans = 1; if (cnt[mid] == limit - 1 && s[1] == 'g') ans = limit; if (abs(cnt[right] - cnt[left]) == 2) ans = min(cnt[left], cnt[right]) + 1; } printf("2\n%d\n", ans); fflush(stdout); return 0; }