You are given an elliptical shaped land and you are asked to choose n arbitrary points on its boundary. Then you connect all these points with one another with straight lines (that’s n*(n-1)/2 connections for n points). What is the maximum number of pieces of land you will get by choosing the points on the boundary carefully?
Input
The first line of the input file contains one integer S (0 < S < 3500), which indicates how many sets of input are there. The next S lines contain S sets of input. Each input contains one integer N (0<=N<2^31).
Output
For each set of input you should output in a single line the maximum number pieces of land possible to get for the value of N.
Sample Input:
4
Sample Output:
1
这个题在《入门经典》这本书里的做法是根据欧拉公式,V - E + F = 2。其中V是顶点数,包括所有顶点数和交点数,E是边数,包括椭圆弧和线段被交点分割成的段数,F是面数,包括题目所求和整个椭圆面这个大面。故题目所求 = E - V + 1。但是这样做一定会WA或TL,因为题目中对于输入的要求是3500个不大于2的31次方的数。因此这个题还有一个考点是高精度数的运算。同时网上有个本题的公式,C(n,4) + C(n,2) + 1。虽然无法推到和证明,但是还是可以理解这个公式的正确性的:
如果没有任何一个点,那么这个椭圆只有一个面——它本身。
每当有一条线(暂时不考虑相交),就会因为分割而多出一个面,n个点能组成C(n,2)条线,所以在原来的基础上加上这1 * C(n,2) = C(n,2)个面。
如果每条线都不与另外一条线相交,那么这样就是结果了,可惜的是,因为任意两点都要连线,故必定有相交,而每个相交又会导致多出一个面,而n个点有多少交线呢?n选2可以选出两个点构成一条线,n选4可以选择4个点,这四个点两两相连有且仅有一个交点(不考虑端点),因此n个点有1 * C(n,4) = C(n,4)个交点,导致多出C(n,4)个面。
因此最终的答案就是1 + C(n,2) + C(n,4)。
有了大数类,有了这个公式,这个题AC就不难了。如果像我一样结果看似“正确”但依然WA,就好好检查大数运算的类吧。提一下自己WA的原因:用Bign这个类的童鞋,这个公式是可以化简成(n * n - n * 5 + 18) * (n - 1) * n / 24 + 1的。但是我们写代码是不能这样写的,因为这个类无法减除负数来,所以当n在1-5之间的时候n * n - n * 5会计算出错误结果。改法就是写成n * n + 18 - n * 5……防止负数出现。
AC代码(0.132s):
#include <iostream> #include <cstring> using namespace std; const int maxn = 200; struct Bign { int s[maxn]; size_t len; Bign() { memset(s, 0, sizeof(s)); len = 1; } Bign(int num) { *this = num; } Bign(const char* num) { *this = num; } Bign operator = (const int num) { char s[maxn]; sprintf(s, "%d", num); *this = s; return *this; } Bign operator = (const char* num) { len = strlen(num); for (int i = 0; i < len; i++) s[i] = num[len - i - 1] - '0'; return *this; } ///输出 string str() const { string res = ""; for (int i = 0; i < len; i++) { res = (char)(s[i] + '0') + res; } if (res == "") { res = "0"; } return res; } ///去前导零 void clean() { while (len > 1 && !s[len - 1]) len--; } ///加 Bign operator + (const Bign& b) const { Bign c; c.len = 0; for (int i = 0, g = 0; g || i < max(len, b.len); i++) { int x = g; if (i < len) x += s[i]; if (i < b.len) x += b.s[i]; c.s[c.len++] = x % 10; g = x / 10; } return c; } ///减 Bign operator - (const Bign& b) const { Bign c; c.len = 0; for (int i = 0, g = 0; i < len; i++) { int x = s[i] - g; if (i < b.len) x -= b.s[i]; if (x >= 0) g = 0; else { g = 1; x += 10; } c.s[c.len++] = x; } c.clean(); return c; } ///乘 Bign operator * (const Bign& b) const { Bign c; c.len = len + b.len; for (int i = 0; i < len; i++) for (int j = 0; j < b.len; j++) c.s[i + j] += s[i] * b.s[j]; for (int i = 0; i < c.len - 1; i++) { c.s[i + 1] += c.s[i] / 10; c.s[i] %= 10; } c.clean(); return c; } ///除 Bign operator / (const Bign &b) const { Bign ret, cur = 0; ret.len = len; for (long i = len - 1; i >= 0; i--) { cur = cur * 10; cur.s[0] = s[i]; while (cur >= b) { cur -= b; ret.s[i]++; } } ret.clean(); return ret; } ///模、余 Bign operator % (const Bign &b) const { Bign c = *this / b; return *this - c * b; } bool operator < (const Bign& b) const { if (len != b.len) return len < b.len; for (long i = len - 1; i >= 0; i--) if (s[i] != b.s[i]) return s[i] < b.s[i]; return false; } bool operator > (const Bign& b) const { return b < *this; } bool operator <= (const Bign& b) const { return !(b < *this); } bool operator >= (const Bign &b) const { return !(*this < b); } bool operator == (const Bign& b) const { return !(b < *this) && !(*this < b); } bool operator != (const Bign &a) const { return *this > a || *this < a; } Bign operator += (const Bign &a) { *this = *this + a; return *this; } Bign operator -= (const Bign &a) { *this = *this - a; return *this; } Bign operator *= (const Bign &a) { *this = *this * a; return *this; } Bign operator /= (const Bign &a) { *this = *this / a; return *this; } Bign operator %= (const Bign &a) { *this = *this % a; return *this; } friend istream &operator>>(istream &is, Bign &num) { string s; is >> s; num = s.c_str(); return is; } friend ostream &operator<<(ostream &os, const Bign &num) { os << num.str(); return os; } }; int main(int argc, const char * argv[]) { Bign n; int M; cin >> M; while (M--) { cin >> n; cout << (n * n + 18 - n * 5) * (n - 1) * n / 24 + 1 << endl; } return 0; }