HDU 5047

HDU 5047 Sawtooth


网上看到一个不错的 贴子 ,所以写一篇博客作为学习笔记

因为要尽可能使得相交后的空间更多,则任意的一对 \(M\) 应交于不同的位置,否则产生的点数一定更少

故在最优方案下,任意一对 \(M\) 的交点应该是一样的,由图可得,任意一对的交点数为 \(16\)

再考虑上每个 \(M\) 和边框有两个交点,故图中的点数 \(V=16\cdot C_n^2+2n=8n^2-6n\)

而如果再已知边数 \(E\) ,则可根据欧拉公式 \(V-E+F-T=1\) 由于三维的 \(T=0\) ,故即可求解出分割出的面数 \(F=E-V+1\)


故考虑如何求出边数 \(E\)

我们考虑一个很极限的情况:图形是近乎无穷大的

而每个 \(M\) 的中间拐点在接近出发的边框处,两个外边的拐点在接近另一处的边框处,但没有相交

故可以视为 \(M\) 的四条边是近乎相互平行的四条边

而在之前的假设中,任意一对 \(M\) 都应该尽可能相交,故 \(M\) 的四条边都被其他 \((n-1)\)\(M\) 划分出了 \(4(n-1)\) 个分割点,产生了 \(4(n-1)+1\) 段边

故四条平行的边,对 \(E\) 的贡献就是 \(4n[4(n-1)+1]=16n^2-12n\)

其次,再考虑和边框的交点,每个 \(M\) 与边框产生 \(2\) 个交点, \(n\)\(M\) 即为 \(2n\) 个交点,把成环的边框分成了 \(2n\)

最后,再考虑 \(M\) 的三个拐点。在上面的 \(4(n-1)+1\) 段边中,我们把它们两边的边视为了不同的边

但实际上,这些拐点并不是交点,因此它们两边的边实际上不能视为不同的边。故每个拐点重复计算了一次,一个 \(M\) 计算了 \(3\) 次,总的重复计算了 \(3n\)

最后得到 \(E=16n^2-12n-3n+2n=16n^2-13n\)


合成得到 \(F=E-V+1=8n^2-7n+1\) ,考虑秦九韶算法可整理成 \(F=(8n-7)n+1\)

由于 \(n\leq 10^{12}\) 我们估计一下最后的大小:

该结果为开口向上的二次函数,最大值在端点处取到,显然不是 \(1\) 处,故为 \(8\times 10^{24}-7\times 10^{12}+1\geq 7\times 10^{24}\) 已经超过 long long 了

long long 的最大值大概在 \(10^{18}\)

不过很显然,答案不超过 \(8\times 10^{24}\) ,而 \(\text{lb }(8\times 10^{24})=3+24\text{lb }10\leq 3+24\text{lb }16=3+24*4=99\leq 128\)

因此可以用 __int128 水过去

记得 __int128 不支持输入输出,需要手写即可


【代码】

#include<bits/stdc++.h>
using namespace std;
inline __int128 read(){
    register __int128 ans=0;register char c=getchar();while(c<48||c>57) c=getchar();
    while(c>=48&&c<=57) ans=ans*10+c-48,c=getchar();
    return ans;
}
inline void output(__int128 ans){
    char s[128]={0},*p=s+126;
    while(ans) *(p--)=ans%10+48,ans/=10;
    puts(p+1);
}
int main(){
    __int128 T=read(),N;
    for(int i=1;i<=T;i++)
        N=read(),printf("Case #%d: ",i),output( (8*N-7)*N+1 );
    return 0;
}
posted @ 2020-07-21 11:34  JustinRochester  阅读(115)  评论(0编辑  收藏  举报