题目传送门
题意:
有一个 的矩阵,把每个格子想象成一个小鱼池,每个鱼池最多可以放一条鱼。
你有一个 的渔网,捕鱼时渔网覆盖的每个位置都必须在矩阵内。每次渔网覆盖范围内的鱼都可以捕获。
现在你有 条鱼,你可以放置鱼的位置,使任意摆放渔网的位置捕获鱼的个数期望最大。
数据范围: 。
题解:
看到题目后感觉可能是推一个结论。
但是看到数据范围发现基本只能是一条一条地摆放每条鱼了。
观察后发现鱼越靠近中间,贡献越多。
中间位置认为是 。
然后再观察发现中间位置的旁边紧邻的上下左右的位置是贡献的次大值。
这就可以 了。
把一条鱼放在 的贡献是
。
计算这个贡献时建议画个图,列不等式方程组。
然后我们累加 条鱼的贡献,最后还需要除渔网的摆放位置方案数。
渔网的摆放位置方案数是 。
感受:
好久没有不看题解1A了,虽然不是什么难题,不过还是比较舒服。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e5 + 5 ;
int row[4] = {-1 , 1 , 0 , 0} ;
int col[4] = {0 , 0 , -1 , 1} ;
int n , m , r , k ;
double sum = 0 ;
map<int , bool> vis[maxn] ;
ll cal(int x , int y)
{
int p = max(1 , x - r + 1) ;
int q = min(x , n - r + 1) ;
int s = max(1 , y - r + 1) ;
int t = min(y , m - r + 1) ;
return ll(q - p + 1) * (t - s + 1) ;
}
struct node
{
int x , y ;
bool operator < (const node &s) const
{
return cal(x , y) < cal(s.x , s.y) ;
}
} ;
priority_queue<node> q ;
bool can(int x , int y)
{
return x >= 1 && x <= n && y >= 1 && y <= m && !vis[x].count(y) ;
}
void bfs()
{
q.push(node{(n + 1) / 2 , (m + 1) / 2}) ;
vis[(n + 1) / 2][(m + 1) / 2] = 1 ;
while(k)
{
int x = q.top().x ;
int y = q.top().y ;
q.pop() ;
sum += (double)cal(x , y) ;
k -- ;
for(int i = 0 ; i < 4 ; i ++)
{
int nx = x + row[i] ;
int ny = y + col[i] ;
if(can(nx , ny))
{
vis[nx][ny] = 1 ;
q.push(node{nx , ny}) ;
}
}
}
}
int main()
{
double ans ;
scanf("%d%d%d%d" , &n , &m , &r , &k) ;
bfs() ;
ans = double(n - r + 1) * (m - r + 1) ;
ans = (double)sum / ans ;
printf("%.12f\n" , ans) ;
return 0 ;
}