1 条题解

  • 0
    @ 2026-4-29 23:50:12

    因为 $\min(\dfrac{a}{b},\dfrac{c}{d})\le \dfrac{a+c}{b+d}\le \max(\dfrac{a}{b},\dfrac{c}{d})$,所以一定不存在多个人在不同州同时演讲的情况。集中力量办大事!

    并且在最优解中,一个州 ii 的演讲时长要么是 00 ,要么是 AiA_iBi(Bi1)B_i(B_i\not= -1)

    考虑当前已经确定了每个州的演讲时长,确定一种演讲顺序使得时间最短。

    因为每次一定是 Rie 和所有的合作者在同一个州演讲,所以时间就是每个州的演讲时长的带权和(演讲时长除以演讲人数)。

    如果一个州的演讲时长是 AiA_i 称该州为 “支持州”,如果一个州的演讲时长是 BiB_i 称该州为 “合作州”,如果一个州的演讲时长为 00 称该州是 “反对州”。

    那么考虑确定一种演讲的顺序使得带权时间和最小,任意一个 “支持州”一定不会在 “合作州”之前进行演讲。

    然后考虑 “合作州” 之间的顺序,根据排序不等式(顺序和>=乱序和>=反序和)一定是按 BiB_i 排序后从小到大的顺序演讲最优。

    那么我们只需要确定“合作州”的个数,“合作州”与“支持州”都是那些州就能够唯一确定该条件下的最优解了。

    那么一个朴素的做法是将所有州按 BB 排序,枚举 “合作州” 个数,然后去做 O(n3)O(n^3) 的 DP f[i,j,k]f[i,j,k] 为前 ii 个州中有恰好 jj 个 “合作州” kk 个“支持州”的最小时间。

    但是我们可以发现最优解中最后一个 “合作州”与其前一个 “合作州” 之间的所有州一定是 “支持州”,因为如果之间存在一个 “反对州”,将最后一个 “合作州” 移动到该州一定更优。

    进而可以推出:第 ii 个“合作州”与第 i+1i+1 个“合作州”之间的所有州均是 “支持州”。

    那么我们可以将 O(n3)O(n^3) 的 DP 简化成 O(n2)O(n^2) 的 DP f[i,j]f[i,j] 表示前 ii 个州中选恰好 jj 个 “合作州” 的最小花费。

    #include <bits/stdc++.h>
    
    #define rep(i,l,r) for (int i = l; i <= r; i++)
    #define per(i,r,l) for (int i = r; i >= l; i--)
    #define fi first
    #define se second
    #define prt std::cout
    #define gin std::cin
    #define edl std::endl
    
    namespace wxy{
    
    const int N = 505;
    
    double f[N][N];
    
    int n,K;
    
    int A[N],B[N],p[N],temp[N];
    
    double get(int k) {
        rep(i,1,n) temp[i] = A[p[i]];
        rep(i,0,n) rep(j,0,n) f[i][j] = 1000000000;
        f[0][0] = 0; double res = 1000000000;
        rep(i,1,n) rep(j,0,std::min(k,i)) {
            f[i][j] = f[i-1][j] + ((double)A[p[i]]/(k+1));
            if (j >= 1 && B[p[i]] != -1) f[i][j] = std::min(f[i][j],f[i-1][j-1]+((double)B[p[i]]/j));
        }
        rep(i,K,n) res = std::min(res,f[i][k]);
        per(i,K-1,k) {
            std::sort(temp+i+1,temp+n+1);
            double val = 0;
            rep(j,1,K-i) val += temp[i+j];
            res = std::min(res,f[i][k] + ((double)val/(k+1)));
        }
        return res;
    }
    
    inline void main(){
        #ifndef ONLINE_JUDGE
            freopen("in.in","r",stdin);
            freopen("out.out","w",stdout);
        #endif
        gin >> n >> K; rep(i,1,n) gin >> A[i] >> B[i]; rep(i,1,n) p[i] = i;
        std::sort(p+1,p+1+n,[](int x,int y){if (~B[x] && ~B[y])return B[x] < B[y]; else return B[x] > B[y];});
        double ans = 1000000000;  
        
        rep(i,0,K) ans = std::min(ans,get(i));
        prt << ans; 
    }
    
    }signed main(){wxy::main(); return 0;}
    
    • 1

    [JOI 2022 Final] 让我们赢得选举 / Let's Win the Election

    信息

    ID
    9047
    时间
    1600ms
    内存
    1024MiB
    难度
    9
    标签
    递交数
    48
    已通过
    4
    上传者