Codeforces 912D Fishes

思路

靠中间的位置自然是最好的,可以用一个函数计算出一个位置对答案的贡献。建立一个按贡献排序的优先队列,先把最中间的位置放入。
然后进行取出,每取出一个,就把它相邻且没有放入过的元素放入优先队列,这样取出k个,就是最优的k个。
自己想的直接按贡献大小分类实现过于复杂,应把计算量交给电脑来做,想出逻辑简单,易于实现的算法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include "stdio.h"
#include "cstring"
#include "stdlib.h"
#include "map"
#include "string"
#include "iostream"
#include "set"
#include "queue"
#include "list"
#include "vector"
#include "algorithm"
#define FOP freopen("input.txt","r",stdin)
#define Met(x,y) memset(x,y,sizeof x)
using namespace std;
typedef long long ll;
const ll MAXN=2e5+100;
const ll MOD=1e9+7;

struct gridc{
ll x,y;
ll ct;
bool operator < (const gridc &a)const{
return ct<a.ct;
}
gridc(ll xx,ll yy,ll cct):x(xx),y(yy),ct(cct){}
};
ll p,q,n,m,k;
struct grid{
ll x,y;
bool operator < (const grid &a)const{
return x*(ll)1e5+y<a.x*(ll)1e5+a.y;
}
grid(ll xx,ll yy):x(xx),y(yy){}
};
ll getct(ll x,ll y)
{
ll ax,ay,bx,by;
ax=max(0LL,x-p+1);
ay=max(0LL,y-q+1);
bx=min(n-q,x);
by=min(m-q,y);
return (bx-ax+1)*(by-ay+1);
}
priority_queue<gridc> pq;
set<grid> vis;
ll dir[4][2]={-1,0,1,0,0,1,0,-1};
int main(int argc, char const *argv[]) {
// FOP;
cin>>n>>m>>p>>k;
q=p;
pq.push(gridc(n/2,m/2,getct(n/2,m/2)));
vis.insert(grid(n/2,m/2));
ll tct=0;
for(int i=0;i<k;++i)
{
tct+=pq.top().ct;
gridc cur=pq.top();
pq.pop();
// printf("x=%lld y=%lld ct=%lld\n",cur.x,cur.y,cur.ct);
for(int j=0;j<4;++j)
{
ll nx=cur.x+dir[j][0],ny=cur.y+dir[j][1];
if(nx<0 || nx>=n || ny<0 || ny>=m || vis.count(grid(nx,ny))) continue;
vis.insert(grid(nx,ny));
// printf("nx=%lld ny=%lld ct=%lld\n", nx,ny,getct(nx,ny));
pq.push(gridc(nx,ny,getct(nx,ny)));
}
}
printf("%.10lf",(double)tct/((n-p+1)*(m-p+1)));
return 0;
}