2024ICPC沈阳VP

题目
wqz秒了三个,gym切了好几个思路没过,我全程卡在b题坐牢,悲惨的一生。
戏剧性的是gym把k题思路切出来了,而k题正式赛时连jly都没有过。。可能这就是物理竞赛神力吧。
3题铜牌。队友过的题这里也会重新写一下,尽力补完medium。
没写思路的题指路qz哥哥题解,这里主要就是放代码

J
#include <bits/stdc++.h>
using namespace std;
void solve() {
    map<int, string>mp1, mp2;
    for (int i = 1; i <= 4; i++) {
        int x;string s;cin >> s>> x; 
        mp1[-x] = s;
    }
    for (int i = 1; i <= 4; i++) {
        int x;string s;cin >> s>> x; 
        mp2[-x] = s;
    }
    if (mp1.begin()->first < mp2.begin()->first) {
        cout << mp1.begin()->second << " beats " << mp2.begin()->second;
    }
    else {
        cout << mp2.begin()->second << " beats " << mp1.begin()->second;

    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    // cin >> t;
    while(t--) {
        solve();
    }
}
D
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 7;
using i64 = long long;
void solve() {
    int n;
    cin >> n;
    vector<int>a(n + 1), b(n + 1);
    vector<pair<int, int>> v(n + 1, {0, 0});
    int sum = 0;
    vector<int>vis(n + 1, 0);
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) cin >> b[i];

    for (int i = 1; i <= n; i++) v[i] = {a[i], b[i]};
    sort(v.begin(), v.end());
    for (int i = 1; i <= n; i++) {
      int x = i;
      if (vis[x]) continue;
      ++sum;
      while (!vis[x]) {
        vis[x] = 1;
        x = v[x].second;
      }
    }
    int ans = (n % 2 != sum % 2);
    cout << (ans ? 'A' : 'B');
    for (int i = 1; i < n; i++) {
        char c; int t, l, r;
        cin >> c >> l >> r >> t;
        if ((r - l) % 2 == 1 && t % 2 == (r - l) % 2) {
            ans ^= 1;
        }
        cout << (ans ? 'A' : 'B');
    }
    cout << '\n';
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    cin >> t;
    while(t--) {
        solve();
    }
}
E
B
M

G

伪装成计算几何的数学题。。
完全想错思路了,求面积却一直想着如何求出正确的多边形长啥样。。
\(f(x)\) 表示对应x的询问结果,发现是线性分段函数,积分可得面积,分为两种情况讨论。

  1. x坐标没有重复的 (直接问中间的n-2个点即可)
  2. x坐标有重复的(问分段中点求解)
    这里r和s是分数,用long double精度够,还有一个就是发现面积两倍是整数且在2e6范围内,可以乘法逆元自己找质数取模算,非常神奇。
code
```cpp
#include <bits/stdc++.h>
using namespace std;
const int N = 1048576 + 7, mod = 998244353;
#define ld long double
#define pild pair<int, ld>
int n, m, r, s;
long double que(int x, int y) {
    cout <<"? " << x << ' '<< y << endl;
    long double r, s; cin >> r >> s;
    return r / s;
}
void solve() {
    cin >> n;
    bool rep = 1;
    set<int>st;
    for (int i = 1; i <= n; i++) {
        int x, y; cin >> x >> y;
        st.insert(x);
    }
    if (st.size() == n) rep = 0;
    set<int>::iterator it;
    vector<ld>vt;
    for (it = st.begin(); it!= st.end(); it++) vt.push_back(*it);
    ld l1 = 0, l2 = 0;
    ld ans = 0;
    if (rep) {
        for (int i = 1; i < vt.size(); i++) {
            ans += ((vt[i] - vt[i - 1]) * (que(vt[i] + vt[i - 1], 2)));
        }
    }
    else {
        for (int i = 1; i < vt.size(); i++) {
            if (i == vt.size() - 1) {
                ans += (vt[i] - vt[i - 1]) * (l1)/2;
                break;
            }
            l2 = que(vt[i], 1);
            ans += ((vt[i] - vt[i - 1]) * (l1 + l2)) / 2;
            l1 = l2;
        }
    }
    ans *= 2;
    int a = round(ans);
    if (a % 2 == 0) cout << "! " << a/2 << ' ' << 1 << endl;
    else cout << "! " << a << ' ' << 2 << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
    cin >> t;
    while(t--) {
        solve();
    }
}
```

H

最大难点在于读懂题意。
求dfs操作时在完全图中能选的合法子集方案。
观察出以下几点性质:

  1. \(u\) 可连边的点为大于\(v_max\) 的子树内点, 若此类点有k个,方案数为 \(2^k\)
  2. 1所在树大小为n-1时可以不经过特殊边
  3. 求解答案只需要对所有连接两棵树的方案求和,设连接点为(p,q),1为根的树为T1,另一棵树为T2
  • T1内连边方案与p,q无关,dfs序排列后子树是连续的区间,在区间内找出最大v然后转换为二维数点问题
  • T2内连边方案是以q为根的方案数与p无关,按dfs序排列后主席树求解
  • T1T2之间连边方案在1~p的链上点和T2内点产生与q无关,也就可以直接枚举p然后累计求答案
  • 将1,2答案和,3答案和乘起来就是最后答案

贴一个类似使用dfs序+主席树二维数点的题目,感觉也要成为经典思路了。

code

K

等gym大神发题解中

posted @ 2025-03-05 20:00  lyrrr  阅读(584)  评论(0)    收藏  举报