[luogu]P2123 皇后游戏

题目传送门

分析

和国王游戏一样的思路直接考虑邻项交换
观察易知排在后面的大臣获得的奖赏一定更多
假设前 \(i - 1\) 位左手上的数和为\(a\),第 \(i - 1\) 位获得奖赏为\(c_{i - 1}\);
对于排在第 \(i\) 位和第 \(i + 1\) 位的大臣,
交换前,最大收益

\[w1 = max(c_i,\sum_{j=1}^{i+1}a_j)+b_{i+1}=…… \\=max(c_{i-1}+b_i+b_{i+1},\sum_{j=1}^ia_j+b_i+b_{i+1},\sum_{j=1}^{i+1}a_j+b_{i+1}) \]

交换后,最大收益

\[w2 = max(max(c_{i-1},\sum_{j=1}^{i-1}a_j+a_{i+1})+b_{i+1},\sum_{j=1}^{i+1}a_j)+b_i=…… \\=max(c_{i-1}+b_i+b_{i+1},\sum_{j=1}^{i-1}a_j+a_{i+1}+b_i+b_{i+1},\sum_{j=1}^{i+1}a_j+b_{i}) \]

为了使交换前收益最小需要满足 \(w1 < w2\) ,则有

\[max(\sum_{j=1}^ia_j+b_i+b_{i+1},\sum_{j=1}^{i+1}a_j+b_{i+1})<max(\sum_{j=1}^{i-1}a_j+a_{i+1}+b_i+b_{i+1},\sum_{j=1}^{i+1}a_j+b_{i})\\max(a_i+b_i+b_{i+1},a_i+a_{i+1}+b_{i+1})<max(b_i+b_{i+1}+a_{i+1},a_i+b_i+a_{i+1})\\max(b_i,a_{i+1})+a_i+b_{i+1}<max(b_{i+1},a_i)+b_i+a_{i+1}\\max(-a_{i+1},-b_i)<max(-a_i,-b_{i+1})\\min(a_{i+1},b_i)>min(a_i,b_{i+1})\\min(a_i,b_{i+1})<min(a_{i+1},b_i) \]

所以只需要按这个规定贪心排序即可,个人认为传递性是存在的,手推了一下满足条件的所有情况,都没有矛盾(就是懒得用反证法)
但是没有考虑的是当 \(min(a_i,b_{i+1})=min(a_{i+1},b_i)\) 时应该如何排序
在一个相对的平衡里,如果我的某一方面属性在局面里有较大作用(比方说右手数字比你大,因为计算时最后直接加的右手数字)那么把我排在你前面才能使答案缩小,所以在这个平衡状态里我选择把右手数字大的排在前面。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define rg register
inline int read(){
    rg int x = 0, f = 1;
    rg char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x * f;
}
const int N = 2e4 + 1;
struct minister{
    int l, r;
    bool operator <(minister b) const{
        if (min(l, b.r) == min(r, b.l))
            return l < b.l;
        return min(l, b.r) < min(r, b.l);
    }
    /*int l, r, d;
    bool operator < (minister b) const{
        if (d != b.d) return d < b.d;
        if (d < 0) return l < b.l;
        else return r > b.r;
    }*/
}a[N];
int n;
long long sum;
long long c[N];
inline void init(){
    n = read();
    for (int i(1); i <= n; ++i){
        a[i].l = read(), a[i].r = read();
    /*    if (a[i].l > a[i].r) a[i].d = 1;
        else if (a[i].l < a[i].r) a[i].d = -1;
        else a[i].d = 0;*/
    }
    sum = 0;
}
inline void doit(){
    sort(a + 1, a + 1 + n);
    for (int i(1); i <= n; ++i){
        sum += a[i].l;
        c[i] = max(c[i - 1], sum) + a[i].r;
    }
    printf("%lld\n", c[n]);
}
int main(){
    ios::sync_with_stdio(false);
    cout.tie(NULL);
    int T = read();
    while (T--){
        init();
        doit();
    }
    return 0;
}
posted @ 2023-01-09 22:03  ancer  阅读(19)  评论(0)    收藏  举报