P6269 [SHOI2002]空中都市 题解

CSDN同步

原题链接

简要题意:

求在 \(n\) 个点中满足每 \(3\) 个点不两两有边的最多边数。

首先,这题 \(\text{dp}\) 没有头绪,所以只能手动找规律。

\(\texttt{n}\) \(0\) \(1\) \(2\) \(3\) \(4\) \(5\) \(6\)
\(\texttt{ans}\) \(0\) \(0\) \(1\) \(2\) \(4\) \(6\) \(9\)

如果你不明白,这里给出 \(n>3\) 的所有构造图(\(n \leq 3\) 就不用画图了吧)

\(n=4\) 时答案为 \(4\):


\(n=5\) 时答案为 \(6\):

\(n=6\) 时答案为 \(9\):

所以,我们在看一眼这个表格:

\(\texttt{n}\) \(0\) \(1\) \(2\) \(3\) \(4\) \(5\) \(6\)
\(\texttt{ans}\) \(0\) \(0\) \(1\) \(2\) \(4\) \(6\) \(9\)

然后,因为我们觉得可以 \(O(1)\) 用公式计算,盲猜它次数应该不会超过 \(4\) 次,所以就假设答案 \(f_x = ax^4 + bx^3 + cx^2+dx+ e\).

然后得到方程组:

\[ \begin{cases} a + b + c + d + e = 0 \\ 16a + 8b + 4c + 2d + e = 1 \\ 81a + 27b + 9c + 3d + e = 2 \\ 256a + 64b + 16c + 4d + e = 4 \\ 625a + 125b + 25c + 5d + e = 6 \\ 1256a + 216b + 36c + 6d + e = 9 \end{cases} \]

(好像还多了一道方程)

你发现答案 近似 为:

\[ \begin{cases} a=0 \\ b=0 \\ c=\frac{1}{4} \\ d=0 \\ e=0 \end{cases} \]

即答案为 \(\bigg( \frac{ n^2}{4} \bigg )\).

你整理一下发现,答案其实是:

\[\bigg \lfloor \frac{n^2}{4} \bigg \rfloor \]

然后你就用 \(O(1)\) 解决了问题。

下面给出一个 严谨 一点的解法。

下面资料来自 百度百科——托兰定理

\(A\)\(N\) 个点中,向外连线最多的点,设它向外连 \(k\) 条线,则与 \(A\) 相连的点之间不允许连线

而剩余 \(N-1-k\) 中的任意一点不可能向外连线数大于 \(k\),设这些点连线总数为 \(y\),则有

\(y≤k(N-1-k)+k\)

\(y≤-k^2+Nk=-(k-N/2)^2+ \lfloor N^2/4 \rfloor\)

\(k= \lfloor N/2 \rfloor\) 时,\(y\) 是整数,所以 \(y\)的最大值为\(\lfloor N^2/4 \rfloor\)

所以 \(y≤ \lfloor N^2/4 \rfloor\)

得证。

时间复杂度:\(O(1)\).

实际得分:\(100pts\).

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;

inline int read(){char ch=getchar();int f=1;while(ch<'0' || ch>'9') {if(ch=='-') f=-f; ch=getchar();}
	int x=0;while(ch>='0' && ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x*f;}

int main(){
	int n=read();
	printf("%d\n",n*n/4);
	return 0;
}

posted @ 2020-04-02 19:39  bifanwen  阅读(262)  评论(0编辑  收藏  举报