2021牛客暑期多校训练营8 K题: Yet Another Problem About Pi

K题: Yet Another Problem About Pi

原题链接:https://ac.nowcoder.com/acm/contest/11259/K

题目大意

在二维平面上,在x轴方向上每 w w w km画一条竖线,在y轴方向上每 d d d km画一条横线,这些线将平面分割为若干个 w × d w\times d w×d 大小的矩形区域。
求从任意点开始,以任意形式的路径行驶 π \pi π km,最多可以访问到多少区域。

题解

首先考虑一下访问的出发点,若我们从一个点出发,则我们可以移动微小的距离(小到不影响精度范围内,而且因为 π \pi π 是无理数,可以理解为其极后的一个数位发生了变动,可以不计)来直接访问周围的 4 4 4 个区域,显然,这是最优的。
两点之间线段最短,因此我们尽量考虑走直线,首先显而易见的,我们移动 min ⁡ ( w , d ) \min(w,d) min(w,d) 的距离(即较短边)来达到一个相邻的点,然后微动访问 2 2 2 个新区域,如下图(蓝色起始,绿色为新增,红色为路径):
在这里插入图片描述
但还有一种方案,我们走单个区域的对角线( w 2 + d 2 \sqrt{w^2+d^2} w2+d2 )来到达一个相邻的点,不难发现,此时微动访问的新区域数量变为了 3 3 3 个,如下图(蓝色起始,绿色为新增,红色为路径):
在这里插入图片描述
显然,最终区域数与两种方案的执行顺序无关(平面无限大),只与两种方案的执行数量有关。
我们设 a = min ⁡ ( w , d ) , b = w 2 + d 2 a=\min(w,d),b=\sqrt{w^2+d^2} a=min(w,d),b=w2+d2 ,则问题转化为求满足 a x + b y ≤ π ax+by\le \pi ax+byπ 的非负整数 x , y x,y x,y 代入 2 x + 3 y 2x+3y 2x+3y 中得到的最大值。
显然,我们可以考虑优先采取区域/代价比 a 2 \frac{a}{2} 2a b 3 \frac{b}{3} 3b 更优者来接近最优解:

  1. a 2 < b 3 ( 3 a < 2 b ) \frac{a}{2}<\frac{b}{3}(3a<2b) 2a<3b(3a<2b) 则可以采用 2 y ( 6 区 域 ) ⟶ 3 x ( 6 区 域 ) 2y(6区域)\longrightarrow 3x(6区域) 2y(6)3x(6) 的方式在不减少区域的前提下减少花费(可能节省以得到更多操作次数);
  2. b 3 < a 2 ( 2 b < 3 a ) \frac{b}{3}<\frac{a}{2}(2b<3a) 3b<2a(2b<3a) 则可以采用 3 x ( 6 区 域 ) ⟶ 2 y ( 6 区 域 ) 3x(6区域)\longrightarrow 2y(6区域) 3x(6)2y(6) 的方式在不减少区域的前提下减少花费(可能节省以得到更多操作次数);
  3. a 2 = b 3 ( 3 a = 2 b ) \frac{a}{2}=\frac{b}{3}(3a=2b) 2a=3b(3a=2b) 则任选(实际操作优先选择增加 x x x ( a a a 操作次数)会更优,因为单步花费少更容易细分利用路径长度);

根据以上转换规则,不难发现在最终完全单向转化后的非负整数 x , y x,y x,y 中, x < 3 x<3 x<3 y < 2 y<2 y<2 至少成立一条,则我们枚举其中一者的数量为 0 0 0~ 2 2 2 ,然后计算最大化利用路径得到的解即可。

补: 关于为什么解可能不是单种操作

只使用单种操作,最终结果可能会有较大浪费(剩余长度不足以执行任何一种长度),此时若减少原优先操作,改为另一种实现更优的路径长度利用,则可能得到更优解。
y < 2 ( 优 先 x ) y<2(优先x) y<2(x) 时可能发生的转化来源:
⌊ x ⌋ = 1 ( 区 域 数 2 ) ⟶ ⌊ y ⌋ = 1 ( 区 域 数 3 ) \lfloor x\rfloor =1(区域数2)\longrightarrow \lfloor y\rfloor =1(区域数3) x=1(2)y=1(3)

x < 3 ( 优 先 y ) x<3(优先y) x<3(y) 时可能发生的转化来源:
⌊ y ⌋ = 1 ( 区 域 数 3 ) ⟶ ⌊ x ⌋ = 2 ( 区 域 数 4 ) \lfloor y\rfloor =1(区域数3)\longrightarrow \lfloor x\rfloor =2(区域数4) y=1(3)x=2(4)

参考代码

#include<bits/stdc++.h>
#define ll long long
#define For(i,n,m) for(int i=n;i<=m;i++)
#define FOR(i,n,m) for(int i=n;i>=m;i--)
using namespace std;
void read(int &x){
   int ret=0;
   char c=getchar(),last=' ';
   while(!isdigit(c))last=c,c=getchar();
   while(isdigit(c))ret=ret*10+c-'0',c=getchar();
   x=last=='-'?-ret:ret;
}

const double p=acos(-1);//通过acos(-1)获得pi的值
int T,ans;
double w,d,fi;

int main()
{
   read(T);
   while(T--){
   	scanf(" %lf %lf",&w,&d);
   	ans=0;
   	double fi=min(w,d),se=sqrt(w*w+d*d);//预处理
   	For(i,0,2){//考虑单种0~2
   		if(p-i*fi>0)ans=max(ans,(int)((p-i*fi)/se)*3+2*i);//i为走短边次数,注意保证此时走对角线次数非负
   		if(p-i*se>0)ans=max(ans,(int)((p-i*se)/fi)*2+3*i);//i为走对角线次数,注意保证此时走短边次数非负
   	}
   	printf("%d\n",ans+4);
   }
   return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值