题解 CF1552C Maximize the Intersections

又是掉大分场。

赛时前面两题还做得挺快,然后到 C 就卡住了。

\(2n\) 个点排在圆上,满足没有连成的弦三线共点。有 \(k\) 条弦以确定,请连 \((n-k)\) 条弦使交点最多,弦和弦不能共端点。

赛场上一直想着怎么处理新加进去的弦和原来弦的关系,然后就什么也没有想到。

先考虑我们要新连上去的弦的相交关系。把这些点重新编号 \(1 \to 2(n-k)\), 这样的话,\(i\) 和 \(i+n-k\) 相连就是最优的了。因为在这种情况下无论交换哪俩端点都只能使两条弦变得不相交,从而减少交点。
然后再考虑这些弦和原来已有的弦的相交情况。你会惊奇的发现,这样的安排也是最优的,因为交换同样不能让它有更多的交点。

那么构造好再判交点就行了。

代码
#include <iostream>
#include <algorithm>
#include <utility>
#include <vector>
#define mapa std::make_pair
#define fi first
#define se second
const int N = 205;
int T, n, k;
bool inter(std::pair<int, int> x, std::pair<int, int> y) {
    if (x.fi > y.fi) std::swap(x, y);
    return x.se > y.fi && x.se < y.se;
}
int main() {
    std::cin >> T;
    while (T--) {
        std::cin >> n >> k;
        std::vector<std::pair<int, int> > ch;
        std::vector<bool> vis(2*n+1);
        for (int i = 1, x, y; i <= k; i++) {
            std::cin >> x >> y;
            if (x > y) std::swap(x, y);
            ch.push_back(mapa(x, y));
            vis[x] = vis[y] = 1;
        }
        std::vector<int> unu;
        for (int i = 1; i <= 2*n; i++)
            if (!vis[i]) unu.push_back(i);
        for (int i = 0; i < n-k; i++)
            ch.push_back(mapa(unu[i], unu[i+n-k]));
        int ans = 0;
        for (int i = 0; i < n; i++)
            for (int j = i+1; j < n; j++)
                if (inter(ch[i], ch[j])) ans ++;
        std::cout << ans << '\n';
    }
}

其实这题根本不难,赛场上有 \(2000+\) 的人过,但我确实没有什么想法。
平时要对这些没有什么高级技巧的题多练习啊。

上一篇:Shell单分支if语句(1) - 语法格式


下一篇:(转)23 个非常实用的 Shell 拿来就用脚本实例