西安理工大學2024年程式設計校賽(校外同步賽)_ACM/NOI/CSP/CCPC/ICPC演算法程式設計高難度練習賽_牛客競賽OJ (nowcoder.com)
A:簽到篇.上
void solve(){ string s; cin >> s; if(s == "A" || s == "B" || s == "C") cout << "YES\n"; else cout << "NO\n"; }
B:簽到篇.中
typedef tuple<string, string, string> tss; void solve(){ map<tss, string> v; v[{"Vertebrates", "Bird", "Carnivores"}] = "Eagle"; v[{"Vertebrates", "Bird", "Haunted Den"}] = "Pigeons"; v[{"Vertebrates", "Mamifero", "Haunted Den"}] = "People"; v[{"Vertebrates", "Mamifero", "Herbivorous"}] = "Cow"; v[{"Invertebrates", "Insect", "Blood Devouring"}] = "Fleas"; v[{"Invertebrates", "Insect", "Herbivorous"}] = "Caterpillar"; v[{"Invertebrates", "Wrinkle", "Blood Devouring"}] = "Leeches"; v[{"Invertebrates", "Wrinkle", "Haunted Den"}] = "Worms"; string s1, s2, s3; getline(cin, s1); getline(cin, s2); getline(cin, s3); cout << v[{s1, s2, s3}]; }
C:簽到篇.下
void solve(){ string x, y, z; cin >> x >> y >> z; if(x == y && y == z && z == x) cout << "="; else cout << ">"; }
D:座標遊戲
思路:博弈問題,如果後手一直把先手維持在 y = x 上面,假設 s 是小於 sqrt(d * d / 2 * k * k) 的最小整數,如果此時先手任然能走出一步,也就是 (s * s * k * k) + (s * k + s) * (s * k + s) <= d * d 那麼先手必勝,否則的話就是後手獲勝
void solve(){ ll d, k; cin >> d >> k; ll s = sqrt(d * d / (2 * k * k)); if(s * s * k * k + (s * k + k) * (s * k + k) <= d * d) cout << "Parry\n"; else cout << "Mercedes\n"; }
F:數對
思路:每次加入⌊m/a[i]⌋,樹狀陣列維護,修改也就是減去原貢獻,加上新的貢獻即可
struct BIT{ ll n; vector<ll> tr; ll lowbit(ll x){ return x & (-x); } BIT(int _n) : n(_n), tr(n + 10) {} void build(ll n, vector<ll> & arr){ for(int i = 1; i <= n; i ++){ ll fa = i + lowbit(i); tr[i] += arr[i]; if(fa <= n) tr[fa] += arr[i]; } } void add(ll x, ll y){ for(ll pos = x; pos < n; pos += lowbit(pos)){ tr[pos] += y; } } ll query(ll x){ ll res = 0; for(ll pos = x; pos; pos -= lowbit(pos)){ res += tr[pos]; } return res; } ll query(ll l, ll r){ return query(r) - query(l - 1); } }; void solve(){ ll n, q, m; cin >> n >> q >> m; vector<ll> a(n + 1); BIT bit(1000010); for(ll i = 1; i <= n; i ++) cin >> a[i]; // sort(a.begin() + 1, a.end()); ll ans = 0; for(int i = 1; i <= n; i ++){ bit.add(a[i], 1); ll num = m / a[i]; ans += bit.query(num); } while(q --){ ll op, p, x; cin >> op; if(op == 1){ cin >> p >> x; ll num = a[p]; ans -= bit.query(m / num); bit.add(num, -1); bit.add(x, 1); ans += bit.query(m / x); a[p] = x; } else{ cout << ans << '\n'; } } }
G:數字查詢
思路:暴力搜尋
int p(string s, int p) { //s[]為順序儲存的p進位制字串 int x = 0; for (int i = 0; i < s.size(); i++) { x *= p; if (s[i] >= 'A' && s[i] <= 'Z') x += (s[i] - 'A' + 10); else x += (s[i] - '0'); } return x; } void solve(){ int n, ans = 0; cin >> n; int n1 = n; vector<int> a; set<int> st; while(n){ a.push_back(n % 10); n /= 10; } int len = a.size(); auto dfs =[&](auto && dfs, int u, string s) -> void{ if(u == 0){ for(int i = 0; i <= 9; i ++){ char c = '0'; c += i; string s1 = s + c; dfs(dfs, u + 1, s1); } } else{ if(s.size() == len + 1){ ll num = p(s, 10); if(num <= n1){ st.insert(num); } return; } if(s.size() >= 2 && s.size() <= len){ ll num = p(s, 10); if(num <= n1){ st.insert(num); }; } char c1 = s.back(); if(c1 - 2 >= '0'){ string s1 = s; char c2 = c1 - 2; s1 += c2; dfs(dfs, u + 1, s1); } if(c1 + 2 <= '9'){ string s1 = s; char c2 = c1 + 2; s1 += c2; dfs(dfs, u + 1, s1); } } }; string s = ""; dfs(dfs, 0, s); for(auto v : st){ if(v >= 10 && v <= n1) ans ++; } cout << ans << '\n'; }
H:聽歌
思路:賽時寫了一個很麻煩的ST表套單調棧,正解應該是二分答案,二分最小值,把所有小於mid的全部加上這個區間最大值的絕對值,如果還是小於mid,返回false,詳細看程式碼
賽時程式碼:
struct ST{ int n, q; vector<vector<int>> f; ST(int _n) : n(_n), f(25, vector<int>(n + 1, 0)) {} void init(vector<int> & a){ for(int i = 1; i <= n; i ++) f[0][i] = a[i]; for(int j = 1; j <= 20; j ++){ for(int i = 1; i + (1 << j) - 1 <= n; i ++){ f[j][i] = min(f[j - 1][i], f[j - 1][i + (1ll << (j - 1))]); } } } int query(int l, int r){ int len = __lg(r - l + 1); return min(f[len][l], f[len][r - (1 << len) + 1]); } }; void solve(){ int n; cin >> n; vector<PII> a(n + 1); for(int i = 1; i <= n; i ++) cin >> a[i].first >> a[i].second; sort(a.begin() + 1, a.end()); vector<int> b(n + 1); for(int i = 1; i <= n; i ++) b[i] = a[i].second; ST st(n); st.init(b); vector<int> nxt(n + 1, -1), pre(n + 1, -1); stack<int> stk; for(int i = 1; i <= n; i ++){ if(stk.size() == 0 || b[i] < b[stk.top()]) stk.push(i); else{ while(stk.size() && b[i] > b[stk.top()]){ int x = stk.top(); stk.pop(); nxt[x] = i; } stk.push(i); } } while(stk.size()) stk.pop(); for(int i = n; i >= 1; i --){ if(stk.size() == 0 || b[i] < b[stk.top()]) stk.push(i); else{ while(stk.size() && b[i] > b[stk.top()]){ int x = stk.top(); stk.pop(); pre[x] = i; } stk.push(i); } } int ans = -INF; for(int i = 1; i <= n; i ++){ int l = pre[i], r = nxt[i]; if(l == -1) l = 1; else l = l + 1; if(r == -1) r = n; else r = r - 1; int res = st.query(l, r) + abs(b[i]); if(l > 1) res = min(res, st.query(1, l - 1)); if(r < n) res = min(res, st.query(r + 1, n)); // cout << l << ' ' << r << '\n'; ans = max(ans, res); } cout << ans << '\n'; }
正解:
void solve(){ int n; cin >> n; vector<PII> v(n); for(auto & [x, y] : v) cin >> x >> y; sort(v.begin(), v.end()); int l = -1000000000, r = 0; auto check =[&] (int mid) -> bool{ int l = -1, r = - 1; for(int i = 0; i < n; i ++){ if(v[i].second < mid){ if(l == -1) l = i; r = i; } } if(l == -1) return true; int ma = -1e9; for(int i = l; i <= r; i ++){ ma = max(ma, v[i].second); } for(int i = l; i <= r; i ++){ if(v[i].second - ma < mid) return false; } return true; }; while(l < r){ ll mid = l + r + 1 >> 1; if(check(mid)) l = mid; else r = mid - 1; } cout << l << '\n'; }
I:哲學問題
思路:看奇數個數:
1:奇數數量為1,先手必勝;
2:奇數的數量為偶數,先拿到只剩下一個奇數,後手永遠無法消除這個奇數,然後下一輪先手必勝;
3:奇數數量為0,後手必勝
void solve(){ ll n; cin >> n; int jis = 0, ous = 0; for(int i = 1; i <= n; i ++){ ll x; cin >> x; if(x & 1) jis ++; else ous ++; } if(jis != 0) cout << "halo\n"; else cout << "parry\n"; }
J:魔方
思路:噁心大模擬,沒啥思路,幹就完了
#include<bits/stdc++.h> using namespace std; const long double PI = acos(-1); //#define int long long typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PII; int lowbit(int x) {return x & (- x);}; const int N = 200010, mod = 998244353; const int Mod = 1e9 + 7, INF = 0x3f3f3f3f; char mf[30][20]; void init(int x, int y, char c){ for(int i = x; i <= x + 2; i ++){ for(int j = y; j <= y + 2; j ++){ mf[i][j] = c; } } } int dx[] = {-1, -1, -1, 0, 1, 1, 1, 0}; int dy[] = {-1, 0, 1, 1, 1, 0, -1, -1}; void s1(int x, int y){ string s; for(int i = 0; i < 8; i ++) s += mf[x + dx[i]][y + dy[i]]; for(int i = 0; i < 8; i ++){ mf[x + dx[(i + 2) % 8]][y + dy[(i + 2) % 8]] = s[i]; } } void l(){ s1(5, 2); string s; for(int i = 10; i <= 12; i ++) s += mf[i][4]; for(int i = 1; i <= 9; i ++) s += mf[i][4]; for(int i = 1; i <= 12; i ++) mf[i][4] = s[i - 1]; } void r(){ s1(5, 8); string s; for(int i = 4; i <= 12; i ++) s += mf[i][6]; for(int i = 1; i <= 3; i ++) s += mf[i][6]; for(int i = 1; i <= 12; i ++) mf[i][6] = s[i - 1]; } void u(){ s1(2, 5); string s; for(int i = 4; i <= 9; i ++) s += mf[4][i]; for(int i = 6; i >= 4; i --) s += mf[12][i]; swap(mf[4][1], mf[12][6]); swap(mf[4][2], mf[12][5]); swap(mf[4][3], mf[12][4]); for(int i = 1; i <= 9; i ++) mf[4][i] = s[i - 1]; } void f(){ s1(5, 5); string s; for(int i = 4; i <= 6; i ++) s += mf[3][i]; for(int i = 4; i <= 6; i ++) s += mf[i][7]; for(int i = 6; i >= 4; i --) s += mf[7][i]; for(int i = 6; i >= 4; i --) s += mf[i][3]; int idx = 0; for(int i = 4; i <= 6; i ++) mf[i][7] = s[idx ++]; for(int i = 6; i >= 4; i --) mf[7][i] = s[idx ++]; for(int i = 6; i >= 4; i --) mf[i][3] = s[idx ++]; for(int i = 4; i <= 6; i ++) mf[3][i] = s[idx ++]; } void d(){ s1(8, 5); string s; for(int i = 6; i >= 4; i --) s += mf[10][i]; for(int i = 1; i <= 6; i ++) s += mf[6][i]; swap(mf[6][7], mf[10][6]); swap(mf[6][8], mf[10][5]); swap(mf[6][9], mf[10][4]); for(int i = 1; i <= 9; i ++) mf[6][i] = s[i - 1]; } void b(){ s1(11, 5); string s; for(int i = 4; i <= 6; i ++) s += mf[1][i]; for(int i = 4; i <= 6; i ++) s += mf[i][9]; for(int i = 6; i >= 4; i --) s += mf[9][i]; for(int i = 6; i >= 4; i --) s += mf[i][1]; int idx = 0; for(int i = 6; i >= 4; i --) mf[i][1] = s[idx ++]; for(int i = 4; i <= 6; i ++) mf[1][i] = s[idx ++]; for(int i = 4; i <= 6; i ++) mf[i][9] = s[idx ++]; for(int i = 6; i >= 4; i --) mf[9][i] = s[idx ++]; } void solve(){ for(int i = 1; i <= 12; i ++){ for(int j = 1; j <= 9; j ++){ mf[i][j] = ' '; } } init(1, 4, 'y'); init(4, 1, 'o'); init(4, 4, 'b'); init(4, 7, 'r'); init(7, 4, 'w'); init(10, 4, 'g'); string s; cin >> s; int idx = 0; for(auto c : s){ if(c == 'L') l(); if(c == 'R') r(); if(c == 'U') u(); if(c == 'F') f(); if(c == 'D') d(); if(c == 'B') b(); } for(int i = 1; i <= 12; i ++){ for(int j = 1; j <= 9; j ++){ cout << mf[i][j]; } cout << '\n'; } } int main(){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); int t = 1; // cin >> t; while(t --){ solve(); } return 0; }
L:kids 們的字串游戲
思路:模擬
void solve(){ int n, m; cin >> n >> m; string s; cin >> s; vector<pair<char, int>> v; int flag = 1; for(int i = 1; i <= m; i ++){ int op, p; char c; cin >> op; if(op == 1) flag = (flag + 1) % 2; else{ cin >> p >> c; if(p == 1){ if(flag == 1) v.push_back({c, 1}); else v.push_back({c, 0}); } else{ if(flag == 1) v.push_back({c, 0}); else v.push_back({c, 1}); } } } deque<char> q; for(auto c : s) q.push_back(c); for(auto [x, y] : v){ if(y == 1) q.push_front(x); else q.push_back(x); } if(flag == 1){ while(q.size()){ cout << q.front(); q.pop_front(); } } else{ while(q.size()){ cout << q.back(); q.pop_back(); } } }
M:數學問題
思路:處理出在端點處的座標,相交的線段數量=所有線段-不相交的線段
bool cmp(PII & a1, PII & a2){ if(a1.first != a2.first) return a1.first < a2.first; else return a1.second > a2.second; } struct BIT{ int n; vector<ll> a; BIT(int _n) : n(_n + 3), a(n + 1) {} int lowbit(int x) {return x & (- x);}; void add(int x, int y){ for(int pos = x; pos < n; pos += lowbit(pos)){ a[pos] += y; } } ll query(int x){ ll res = 0; for(int pos = x; pos; pos -= lowbit(pos)){ res += a[pos]; } return res; } }; void solve(){ ll n, l, r; cin >> n >> l >> r; vector<PII> v(n + 1); vector<ll> a; for(int i = 1; i <= n; i ++){ ll k, b; cin >> k >> b; ll l1 = l * k + b, r1 = r * k + b; v[i] = pair(l1, r1); a.push_back(r1); a.push_back(r1 - 1); } sort(v.begin() + 1, v.end(), cmp); sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); cout << a.size() << '\n'; map<ll, ll> mp; for(int i = 0; i < a.size(); i ++) mp[a[i]] = i + 1; BIT bit(a.size() + 10); ll ans = 0; for(int i = 1; i <= n; i ++){ ans += bit.query(a.size() + 1) - bit.query(mp[v[i].second - 1]); bit.add(mp[v[i].second], 1); } cout << ans << '\n'; }
O:完美區間
思路:字串雜湊+暴力模擬
struct Hash{ const ll p = 998244353; const ll base = 131; int n; vector<ll> a, c; Hash(int _n) : n(_n), a(n + 10), c(n + 10) {} void build(int n, string & arr){ c[0] = 1; ll res = 0; for(int i = 1; i <= n; i ++){ res = (res * base + arr[i - 1]) % p; c[i] = c[i - 1] * base % p; a[i] = res; } } ll query(ll l, ll r){ ll ans = (a[r] - a[l - 1] * c[r - l + 1] % p + p) % p; return ans; } }; void solve(){ ll n; cin >> n; vector<ll> a(n + 2), b(n + 1); string s; for(int i = 1; i <= n; i ++){ string s1; cin >> s1; a[i] = s.size(); s += s1; for(auto c : s1){ if(c != '0' && c != '1' && c != '8' && c != '6' && c != '9') b[i] = -1; } } ll len = s.size(); a[n + 1] = len; Hash h1(len); h1.build(len, s); for(auto & c : s){ if(c == '6') c = '9'; else if(c == '9') c = '6'; } reverse(s.begin(), s.end()); Hash h2(len); h2.build(len, s); ll ans = 0; for(int i = 1; i <= n; i ++){ if(b[i] != -1){ for(int j = i; j <= n; j ++){ if(b[j] != -1){ ll l = a[i], r = a[j + 1] - 1; ll l1 = len - r - 1, r1 = len - l - 1; auto hashnum1 = h1.query(l + 1, r + 1); auto hashnum2 = h2.query(l1 + 1, r1 + 1); if(hashnum1 == hashnum2){ ans = max(ans, 1ll * (j - i + 1)); } } else{ break; } } } } cout << ans << '\n'; }