1 条题解
-
0
因为 $\min(\dfrac{a}{b},\dfrac{c}{d})\le \dfrac{a+c}{b+d}\le \max(\dfrac{a}{b},\dfrac{c}{d})$,所以一定不存在多个人在不同州同时演讲的情况。集中力量办大事!
并且在最优解中,一个州 的演讲时长要么是 ,要么是 或 。
考虑当前已经确定了每个州的演讲时长,确定一种演讲顺序使得时间最短。
因为每次一定是 Rie 和所有的合作者在同一个州演讲,所以时间就是每个州的演讲时长的带权和(演讲时长除以演讲人数)。
如果一个州的演讲时长是 称该州为 “支持州”,如果一个州的演讲时长是 称该州为 “合作州”,如果一个州的演讲时长为 称该州是 “反对州”。
那么考虑确定一种演讲的顺序使得带权时间和最小,任意一个 “支持州”一定不会在 “合作州”之前进行演讲。
然后考虑 “合作州” 之间的顺序,根据排序不等式(顺序和>=乱序和>=反序和)一定是按 排序后从小到大的顺序演讲最优。
那么我们只需要确定“合作州”的个数,“合作州”与“支持州”都是那些州就能够唯一确定该条件下的最优解了。
那么一个朴素的做法是将所有州按 排序,枚举 “合作州” 个数,然后去做 的 DP 为前 个州中有恰好 个 “合作州” 个“支持州”的最小时间。
但是我们可以发现最优解中最后一个 “合作州”与其前一个 “合作州” 之间的所有州一定是 “支持州”,因为如果之间存在一个 “反对州”,将最后一个 “合作州” 移动到该州一定更优。

进而可以推出:第 个“合作州”与第 个“合作州”之间的所有州均是 “支持州”。
那么我们可以将 的 DP 简化成 的 DP 表示前 个州中选恰好 个 “合作州” 的最小花费。
#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
信息
- ID
- 9047
- 时间
- 1600ms
- 内存
- 1024MiB
- 难度
- 9
- 标签
- 递交数
- 48
- 已通过
- 4
- 上传者