Luogu P9548 雨纷纷 题解 贪心

原题链接

题意(抽象向):

一个 n × m n\times m n×m 的矩形 A A A(空地)中有一个 x × y x\times y x×y 的小矩形 B B B (雨伞)。对矩形 A A A 任意地撒点,每次(天)撒 k k k 个,并返回是否落到矩形 B B B 内,问至少需要多少天、多少雨滴才能确定一个小矩形 B B B

思路(逐步向):

主要思想:贪心。

本题有两个任务,一是求出最少的雨点数 R a i n Rain Rain,二是求出最少的天数 D a y Day Day(天数比雨点数好求,本题为了提升难度把它们倒了一下)。我们先考虑天数怎么求:

天数的求法——

一旦知晓最少雨点数,只要每天都尽可能地多下雨,那么天数一定是最小的。(贪心)

于是求最少天数的函数呼之欲出:

LL Get_Day(LL k,LL Rain){
  if(Rain % k == 0) return Rain / k;
  //正好下完
  else return (LL)Rain / k + 1;
  //多一天处理余数
}

雨滴数的求法——

最少雨滴数怎么求呢?根据题意,我们需要让一些雨点排除一个雨伞的位置。那么有没有一种可能,我们可以用一个雨滴、排除一个雨伞的位置呢?有!

举个例子,当 n = 6 , m = 6 , x = 3 , y = 2 n=6,m=6,x=3,y=2 n=6,m=6,x=3,y=2 时,我们可以像图片中的那样把 6 × 6 6\times 6 6×6 的空地最大地划成 6 6 6 2 × 3 2\times 3 2×3小矩形右边和下面两条的边界划分不出矩形,我们将其排除在外。

划分矩形

接着,我们在每个小矩形两条边界中落雨,排除出一个的标号为 6 6 6 的矩形(其实其它的标号也行),它,就是我们所求得的雨伞。可以证明最少的雨点数就是 可以划分的矩形数 − 1 + 边界数 可以划分的矩形数-1+边界数 可以划分的矩形数1+边界数。(贪心)

降雨

可以划分的矩形数为 n ÷ x × ( m ÷ y ) n \div x \times (m \div y) n÷x×(m÷y)。边界数随情况而定,只要计算一下 n   m o d   x n\bmod x nmodx m   m o d   y m\bmod y mmody,判断一下右边界和下边界存不存在就好了。

代码如下:

LL Get_Rain(LL n,LL m,LL x,LL y){
  if(n % x == 0 && m % y == 0)
  //没有边界
    return n / x * (m / y) - 1;  
  if(n % x == 0 && m % y != 0)
  //有一个右边界
    return n / x * (m / y);
  if(n % x != 0 && m % y == 0)
  //有一个下边界
    return n / x * (m / y);    	  
  return n / x * (m / y) + 1;
  //有两个边界
}

代码(丑陋向):

注意一些细节:

  1. long long
  2. 雨伞不能旋转,所以 n n n 严格对应 x x x m m m 严格对应 y y y

使用了贪心思想,时间复杂度为 O ( 1 ) O(1) O(1)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
LL Get_Rain(LL n,LL m,LL x,LL y){
  if(n % x == 0 && m % y == 0)
    return n / x * (m / y) - 1;
  if(n % x == 0 && m % y != 0)
    return n / x * (m / y);
  if(n % x != 0 && m % y == 0)
    return n / x * (m / y);
  return n / x * (m / y) + 1;
}
LL Get_Day(LL k,LL Rain){
  if(Rain % k == 0) return Rain / k;
  else return (LL)Rain / k + 1;
}
signed main(){
  LL n,m,x,y,k;	
  scanf("%lld %lld %lld %lld %lld",
  &n,&m,&x,&y,&k);
  LL Rain = Get_Rain(n,m,x,y);
  LL Day = Get_Day(k,Rain);
  printf("%lld %lld",Day,Rain);
  return 0;
}

终于看完了!点个赞吧!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值