How Many Pieces of Land?
原文链接 http://huiming.io/2013/06/17/how-many-pieces-of-land.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
分析:《具体数学》第一章有个类似的问题:n条直线最多可以把一个平面分成多少块?如果n条直线把平面分成了m块,那么再加一条直线最多新增n个交点,这n个交点把新的直线分成了n+1段,每一段都把原来的一块区域分成了2块,也就是说新增了n+1块区域。由此有递推公式:
f(n) = f(n - 1) + n
但是本题的不同之处在于:虽然椭圆圆周上的n个点最多能产生n(n - 1)/2条直线,但这些数量的直线并不能产生最多数量的交点,因此不可以套用上面的公式。但我们仍能得到两个关键的启示: <!--more-->
1分块数量与线段有关,线段由交点产生
2递推解题
算法的思想需要借助一些图示,这个Wiki说得比较清楚了。可惜的是,本题用递推的方法解会超时!从递推式又很难推导出封闭形式!不过上面提到的Wiki里还记录了一种使用欧拉公式的拓扑方法,形式比较简单,应用这种方式解就可以AC。但笔者以为,贴出递推式的解法也是有意义的——起码笔者很难想到欧拉公式!
#include <iostream>
#include <vector>
using namespace std;
typedef long long llt;
vector<llt> pieces;
inline void init() {
pieces.reserve(3000);
pieces.push_back(1);
pieces.push_back(1);
pieces.push_back(2);
}
/*
D(N, i) is the increased pieces of land by introducing one edge
from a newly added point to one of the existed N points. i is the
number of the existed point, ranging in [0, N - 1]. Point 0 is the
point that is immediately adjacent to the newly added point. Point
1 is immediately adjacent to point 0, and point i to point i - 1.
The last point, N - 1, is also immediately adjacent to the newly
added point.
llt D(int N, int i) {
return (llt)i * (N - i - 1) + 1;
}
S(N, n) is the Sum of D(N, i), taking all i in [0, n].
*/
inline llt S(llt N, llt n) {
return (N - 1) * (1 + n) * n / 2 - n * (n + 1) * (n * 2 + 1) / 6 + n + 1;
}
void compute(int n) {
for (int i = pieces.size(); i <= n; i++) {
llt last = pieces[i - 1];
llt inc = S(i - 1, i - 2);
last += inc;
pieces.push_back(last);
}
}
inline llt how_many_pieces(int n) {
if (n >= pieces.size())
compute(n);
return pieces[n];
}
int main() {
init();
int s;
cin >> s;
for (int i = 0; i < s; i++) {
int n;
cin >> n;
cout << how_many_pieces(n) << endl;
}
return 0;
}