今天校内模拟赛考了这道题
考场上想了个贪心策略:分别维护两个数组,第一个 (sz1) 按照 ai 升序排序,第二个 (sz2) 按照 bi 升序排序。(后来发现这样做其实不全面,于是稍微改了一下,后面会说)
首先如果确定了在某些州一定要得到协助人,那么得到他们一定要在前往其他州之前;前往各个州得到协助人的顺序应该按照这些州 bi 的顺序,小的在前大的在后,用 sz2 维护。
确定思路是从小到大枚举得到协助人的数目,同时就确定了要先前往那些州,累加这一部分的贡献。之后优先前往 ai 较小的州,如果与之前处理的那一部分重合则直接修正,否则删去 sz1 要选的那一部分中最后一位,保证剩余代价最小。这里排序会出bug,因此改了一下。代码如下:
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
inline int read()
{
int x = 0; char c; bool f = false;
while(!isdigit(c = getchar()))
if(c == '-') f = true;
do{
x = (x << 1) + (x << 3) + (c ^ 48);
}while(isdigit(c = getchar()));
return f ? -x : x;
}
int n, k, rb, tl, tp = 1;
bool arv[5005], dealt[5005];
double mem = 1.0, ans = 0.0, tot = 0.0, sum = 0.0;
struct node
{
int id;
double a;
double b;
}sz[5005], zs[5005];
//选票优先、协作优先
inline bool tic(node a, node b)
{
if(a.a != b.a) return a.a < b.a;
if(a.b != b.b) return a.b > b.b;
return a.id < b.id;
}
inline bool par(node a, node b)
{
if(a.b != b.b) return a.b < b.b;
if(a.a != b.a) return a.a > b.a;
return a.id > b.id;
}
int main()
{
n = read(); k = tl = read();//最坏从最尾部开始
for(register int i = 1; i <= n; ++i)
{
sz[i].a = read();
sz[i].b = read();
sz[i].id = i; zs[i] = sz[i];
}
sort(sz + 1, sz + n + 1, tic);
sort(zs + 1, zs + n + 1, par);
while(zs[tp].b == -1) ++tp;//之后从这里开始即可
for(register int i = 1; i <= k; ++i)
ans += (double)sz[i].a;
rb = min(n, tp + k - 1); tot = ans;
for(register int i = tp; i < rb; ++i)//最不济前面都拿到协作者然后一起攻占最后一个州
{
arv[zs[i].id] = true;
sum = tot; mem += 1.0;
bool rep = false;
for(register int j = 1; j <= tl; ++j)
{
if(arv[sz[j].id] && !dealt[sz[j].id])
{
rep = dealt[sz[j].id] = true;
sum -= (double)sz[j].a;//此时统计出来的就是去掉这些州以后的剩余
}
}
if(!rep) sum -= (double)sz[tl].a, --tl; tot = sum;
sum /= (double)mem; sum += (double)zs[tp].b;
for(register int j = tp + 1; j <= i; ++j)
sum += (double)zs[j].b / (double)(j - tp + 1.0);
ans = min(ans, sum);
}
printf("%.14lf", ans); return 0;
}
//显然如果确定要在这些城市演讲,同时演讲与分开演讲造成的结果相同
//所以要考虑得到选票的容易度和得到协作者的容易度
//处理的时候将双方排个序,每次把协作者里最大的一个拿出来替换掉选票里最大的一个,观察是否有解
//决策造成的结果应该要求单调递减
//亦即不会存在在大的点拿到协作者而在小的点使用的情况
//得到协作者的前提上一定已经得到了选票
//不过如果要求得到这名协作者,先得到一定比后得到优
但是这玩意 WA 得挺惨
请问这种思路的漏洞在什么地方?
(如果能用下面这组样例说明更好)
7
5
393 646
375 666
374 676
320 635
288 668
284 758
333 702
(THX)