题目链接:点击打开链接
题目大意:给出四个整数n,m,r,k,n,m分别代表矩阵的行数列数,r代表渔网的边长,
渔网是一个正方形,k代表鱼的数量,渔网要在所有可以下网的地方捕鱼,捕完之后
将鱼放回原处,可以下网的原则是不超过矩阵的范围,即的渔网所覆盖的地方都是被
矩阵包含的。
要求算出,每次捕到鱼的数量的平均值的最大值。
(数据范围:1 ≤ n,m ≤ 1e5, 1 ≤ r ≤ min(n,m), 1 ≤ k ≤ min(n·m,1e5))
解析:不难算出渔网可以放置(n-r+1)·(m-r+1) 次,题目也给出了,要平均值最大,
那么只要算出所有点被不同位置的渔网所经过的次数,将它们中前k大的相加再除
以总的个数就是最大的平均值了。要做到这个首先要算出坐标为(x,y)的点
被多少渔网包含,不难退出次数是
((x+r-1<=n?x:n-r+1)-(x-r+1>=1?x-r+1:1)+1)*((y+r-1<=m?y:m-r+1)-(y-r+1>=1?y-r+1:1)+1),
即考虑边界的情况下求出横纵坐标下可以放置的渔网数,最后横纵的渔网数相乘即是渔网数。
第二个问题是n*m<=1e10,明显的超时,但是k是小于等于1e5的,所以可以找到一个次数最
多的点以此为起点,广搜,广搜用优先队列,保证次数多的先出队。
代码:
#include<cstdio>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
const int N=100000+10,dx[]={0,0,1,-1},dy[]={1,-1,0,0};
ll n,m,r;
int k;
ll calc(ll x,ll y){
return ((x+r-1<=n?x:n-r+1)-(x-r+1>=1?x-r+1:1)+1)*
((y+r-1<=m?y:m-r+1)-(y-r+1>=1?y-r+1:1)+1);
}
struct P{
ll x,y;
friend bool operator<(const P &p1,const P &p2){
return calc(p1.x,p1.y)<calc(p2.x,p2.y);
}
};
map<ll,bool>mmp;
int main()
{
while(~scanf("%I64d%I64d%I64d%d",&n,&m,&r,&k)){
ll xx=(n-r+1)*(m-r+1);
double sum=0;
priority_queue<P>q;
P p;
p.x=n/2+1;
p.y=m/2+1;
q.push(p);
while(!q.empty()){
p=q.top();
q.pop();
if(!k) continue;
if(mmp[ll(p.x*1000000+p.y)]) continue;
int x=p.x,y=p.y;
sum+=calc(x,y);
mmp[ll(p.x*1000000+p.y)]=1;
k--;
for(int i=0;i<4;i++){
p.x=x+dx[i];
p.y=y+dy[i];
if(p.x>=1&&p.x<=n&&p.y>=1&&p.y<=m){
if(!mmp[ll(p.x*1000000+p.y)])
q.push(p);
}
}
}
printf("%.10lf\n",sum/xx);
mmp.clear();
}
return 0;
}