Skip to main content
Original210 words1 min

题解:P9827 [ICPC 2020 Shanghai R] Sky Garden

Summary

在他人给出的 O(n) 线性 DP 做法基础上,观察到其转移全是线性的,用数学软件把它整理化简为 O(1) 的闭式公式:设 t 为 2m 除以 π 下取整,再由 n、m、t 直接算出 p 与 q 两部分,答案为 p 乘 π 加 q,把原本 O(n 的 3 次方) 的暴力压到 O(1)。

解题思路​

@Nuyoah_awa 的 题解 提供了 O(n)O(n) 的做法。

观察他的代码,不难发现其中的 DP 都是线性的。

经过数学软件的整理优化,可以 O(1)O(1) 实现。

设:

t=⌊2mπ⌋t=\left\lfloor\frac{2m}{\pi}\right\rfloor

则有:

p=t(t+1)×n(n+1)(2n+1)6p=\frac{t(t+1)\times n(n+1)(2n+1)}{6} q=mn(n+1)(6mn−4tn−2t−2n−1+3×[m≠1])3q=\frac{mn(n+1)(6mn-4tn-2t-2n-1+3\times[m\ne 1])}{3} S=pπ+qS=p\pi+q

至此,已成艺术。

O(n3)→O(1)O(n^3)\to O(1)

接下来,我们看看 @sintle 的 人工队 #1 和 @Mrkn_chenyx12 的 人工队 #2 表现。

参考代码​

332 Bcpp
#include <bits/stdc++.h>
using namespace std;

using ll=long long;
const double pi=acos(-1);
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
ll n,m;
cin>>n>>m;
ll t=m*2/pi;
ll p=t*(t+1)*n*(n+1)*(n*2+1)/6;
ll q=m*n*(n+1)*(m*n*6-t*n*4-t*2-n*2-1+(m>1)*3)/3;
cout<<fixed<<setprecision(12)<<p*pi+q<<'\n';
return 0;
}