选举(Let's Win the Election)题解

考场上写的纯贪心,假了,只拿了 \(10 pts\) 分。

显然,对于每个州,演讲时间只有 \(0\)\(a_{i}\)\(b_{i}\) 三种情况。

定义演讲时间为 \(a_{i}\) 的州为 \(A\) 类州(即只获得选票),演讲时间为 \(b_{i}\) 的州为 \(B\) 类州(即获得协作者),演讲时间为 \(0\) 的州为 \(C\) 类州(即不去演讲)。

先去演讲 \(B\) 类州,再去演讲 \(A\) 类州是更优的(人多力量大嘛)。

所以我们按照 \(b_{i}\) 排序。

我的贪心假的原因是:

贪心选择 \(b_{i}\) 最小的州成为 \(B\) 类州,枚举 \(B\) 类州的个数,然后选择剩下的州中 \(a_{i}\) 最小的州成为 \(A\) 类州

这个时候就会有一个问题,在两个州 \(x\)\(y\) 中,\(x\)\(b_{i}\)\(a_{i}\) 都比 \(y\) 的小时,可能选择 \(y\) 比选择 \(x\) 更优,所以贪心就假了。

我们枚举 \(b_{i}\) ,进行 \(dp\)

由于是按照 \(b_{i}\) 升序排列的,那么如果 \(B\) 类州之前存在 \(C\) 类州,让该 \(C\) 类州成为 \(B\) 类州,该 \(B\) 类州成为 \(C\) 类州是更优的。

那么序列的前半部分只有 \(A\) 类州或 \(B\) 类州,后半部分只有 \(A\) 类州或 \(C\) 类州。

所以定义 \(dp_{i,j}\) 表示枚举到第 \(i\) 个州,选了 \(j\)\(B\) 类州的最少时间。

枚举 \(B\) 类州的个数 \(sum\),然后进行 \(dp\)

\(dp\)\(sum\) 后停止,计算剩下的州中最小的 \(A\) 类州的时间。

设后 \(x\) 个州里,\(a_{i}\) 最小的 \(y\) 个州的 \(a_{i}\) 之和为 \(w(x,y)\)

那么答案就是 \(min_{i = sum}^{k}dp_{i,sum} + w(n - i,k - i)\)

\(dp\) 的时间复杂度是 \(\mathcal{O}(n^{2})\),由于要枚举 \(B\) 类州的个数,所以总时间复杂度 \(\mathcal{O}(n^{3})\)

#define Kamisato_Ayaka no tui,juan
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ll long long
#define db double
inline int in(){
    int x = 0;
    bool f = 0;
    char c = getchar();
    while(c > '9' || c < '0'){
        if(c == '-') f = 1;
        c = getchar();
    }
    while(c <= '9' && c >= '0'){
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    if(f) return -x;
    else return x;
}
const int N = 510;
int n,k;
int a[N];
db ans = 1e9;
db dp[N][N];
struct node{
    int a,b;
}q[N];
bool operator < (const node x,const node y){
    return x.b < y.b;
}
inline void work(int x){
    for(int i = 1;i <= n;++i) a[i] = q[i].a;
    for(int i = 0;i <= n;++i)
        for(int j = 0;j <= n;++j) dp[i][j] = 1e9;
    dp[0][0] = 0;
    db res = 1e9;
    for(int i = 1;i <= n;++i){
        for(int j = 0;j <= min(x,i);++j){
            dp[i][j] = dp[i - 1][j] + q[i].a * 1.0 / (x + 1);
            if(j >= 1 && q[i].b != 1e9) dp[i][j] = min(dp[i][j],dp[i - 1][j - 1] + q[i].b * 1.0 / j);
        }
    }
    for(int i = k;i <= n;++i) res = min(res,dp[i][x]);
    for(int i = k;i >= x;--i){
        sort(a + i + 1,a + n + 1);
        db sum = 0;
        for(int j = i + 1;j <= k;++j) sum += a[j];
        res = min(res,dp[i][x] + sum / (x + 1));
    }
    ans = min(ans,res);
}
int main(){
    // fre(a);
    n = in();
    k = in();
    for(int i = 1;i <= n;++i){
        q[i].a = in();
        q[i].b = in();
        if(q[i].b == -1) q[i].b = 1e9;
    }
    sort(q + 1,q + n + 1);
    for(int i = 0;i <= k;++i) work(i);
    printf("%.8lf",ans);
    return 0;
}
posted @ 2022-09-23 15:55  HT_walnut  阅读(96)  评论(0)    收藏  举报