Yet Another Problem About Pi
题目传送门:
题面:
题目大意:
无限多网格,长宽分别给定为 w , d w,d w,d,线的长度是pi,一笔画怎么让这条线经过的网格最多。
思路:
哎,一开始想的就是沿着直线走。
关键点在于长度为无理数,实际上从一个点出发,刚开始就有4个网格可以走到。
那么实际上就是ll ans = 4ll + ll(pi / y) * 2;
但是特殊样例:
2 2
按照以上做法答案是
6
6
6,但是实际上可以达到
7
7
7。
通过走斜对角线实现。
将此作为两个操作当01背包算,因为数据水,可以枚举。
但其实还有点不懂为什么只考虑对角线,不用考虑长为 i i i格,宽为 j j j格的斜线。证明贡献为: ( i + j + 1 ) / √ ( i ∗ w ) 2 + ( j ∗ d ) 2 (i+j+1)/√(i*w)^2+(j*d)^2 (i+j+1)/√(i∗w)2+(j∗d)2,可以计算出对角线的贡献最大,但是对角线的贡献在 b / a > √ 5 / 2 b/a>√5/2 b/a>√5/2时候并没有直线大。
只能说似懂非懂,之后明白了再来补。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
double pi = acos(-1.0);
bool cmp(ll x, ll y) {
return x > y;
}
vector<ll> ans;
int main() {
int t;
cin >> t;
while (t--) {
double w, d;
cin >> w >> d;
double x = sqrt(w * w + d * d);
double y = min(w, d);
ll ans = 4ll + ll(pi / y) * 2;
//整条全是直线。
ll t = 4;
t += ll(pi / x) * 3;
if (pi - ll(pi / x) * x >= y) t += 2;
ans = max(t, ans);
//先走斜线,多的走直线。
for (int i = 0; i < 100; i++) {
double tmp = pi - y * i;
if (tmp < 0)break;
ans = max(ans, 4 + ll(tmp / x) * 3 + i * 2);
//先走直线再走斜线。
}
for (int i = 0; i <= 50; i++) {
double f = pi - x * i;
if (f < 0)break;
ans = max(ans, 4 + ll(f / y) * 2 + i * 3);
//先走斜线再走直线。
}
cout << ans << endl;
}
}
补充
看了下有人写的题解,觉得有道理。
变换情况可能会有影响。
源于
侵删。
参考了Frank_Star的博客
写出了式子:
我觉得很妙。
而且可以证明其他斜线没有对角线优,对角线好就好在可以利用最后多出来的那一部分,把直线的+2变成斜线的+3,浪费的变少了。其他情况其实不如直线+对角来的优。因为能走≥2条直线长度的话一定是走直线更优。