P9827 [ICPC2020 Shanghai R] Sky Garden 题解
Nuyoah_awa · · 题解
题解区目前都是
题目大意
有
对于所有线与圆的交点,从中任取两个,求两点最短路的和。
题目分析
我们不难发现,每个圆上有
DP 大体思路
首先,我们规定圆根据半径从小到大编号为
我们设
对于每个
DP 转移
对于这个点与本层的点的最短路,不难发现,要么通过圆上走来,要么通过半径走来,每个点的最短路通过两值取较小得出,如下图。
对于这个点
首先,我们发现,如果在较小的圆中,这两点的最短路径是从圆上走的,那么另一个圆对应的两点也是从圆上走的,反之同理。于是,我们可以分为两类讨论:
- 两点从圆上走,观察下图,很明显蓝色更优,因为半径更小的弧长也更小。
- 下图中,两点从半径走,则蓝色更优,因为他没必要先向外走再走回来。
综上,我们先从
于是,我们可以得到
其中,
又经过观察发现,
边界状况
首先,对于
根据圆的轴对称性,式子可化简为
而对于
答案求值
答案依旧可以分为两部分算,原理同上,式子为:
所以时间复杂度为
code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#define int long long
#define double long double
using namespace std;
const int N = 505;
int n, m;
double ans = 0, f[N], g[N], tmp, pi = 3.141592653589;
signed main()
{
scanf("%lld %lld", &n, &m);
for(int i = 1;i < m;i++)
tmp += min(i * pi / m, 2.0L);
tmp *= 2;
tmp += 2;
f[1] = g[1] = tmp;
for(int i = 2;i <= n;i++)
{
g[i] = g[1] * i;
f[i] = f[i-1] + 2 * m * (i - 1) + g[i];
}
for(int i = 1;i <= n;i++)
ans += 2 * m * (f[i] - g[i]) + m * g[i] + (m > 1 ? 2 * m * i : 0);
printf("%.10Lf", ans);
return 0;
}