题目描述:
一个圆周上点下了互不重合的N(2≤N≤105)个点,将这N个点两两相连(圆内没有三条线交于一个点的情况),图形中一共有多少个交点(包括边界上的点)。
解析:
同样,这也是一道找规律的题目,将这N个点两两相连,当N>3时,在外部则形成了一个多边形,然后内部的连线则是多边形的对角线,而这道题便转换为多边形内对角线交点个数的问题,即原问题转换成数学问题:
给定一个凸N边形,满足性质:任何三条对角线都不交于同一点.在这样一个多边形的内部,它的所有对角线共形成多少个交点?
由于每一个交点对应着两条相交的对角线,而两条相交的对角线确定一个四边形,所以计算交点的个数即是计算多边形内四边形的个数,所以原问题又转换为多边形内四边形的个数,而四边形四个点,所以这就是我们熟悉的组合问题了(在N个点中任意找四个点形成一个四边形),那么交点个数=四边形个数=C(N,N-4).考虑特殊情况后,很快便得出完整代码:
#include
#include
using namespace std;
typedef long long ll;
int main()
{
int T;
ll N;
while(scanf("%d",&T)==1&&T)
{
while(T--)
{
scanf("%I64d",&N);
if(N==2) printf("2\n");
else if(N==3) printf("3\n");
else if(N>3)
{
ll sum = (N * (N - 1) * (N - 2) *(N - 3)) / 24;
printf("%I64d\n",sum+N);
}
}
}
return 0;
}
提交答案后,却得出这样的回复:
于是,我便开始纳闷,为什么会这样呢?规律都正确了,为什么会得出Wrong Answer呢?
然后我注意到了N的取值范围,N<=10^5,所以我考虑是不是long long的数据范围不够大?于是我很快便得出以下代码:
#include
#include
using namespace std;
typedef unsigned long long ull;
int main()
{
int T;
ull N;
while(scanf("%d",&T)==1&&T)
{
while(T--)
{
scanf("%llu",&N);
if(N==2) printf("2\n");
else if(N==3) printf("3\n");
else if(N>3)
{
ull sum = (N * (N - 1) * (N - 2) *(N - 3)) / 24;
printf("%llu\n",sum+N);
}
}
}
return 0;
}
可依旧还是:
于是我想不明白了,数据改为unsigned long long类型了,已经是整型范围内最大的数据类型了,难道还是超过最大范围吗?于是我重新看了一下N的取值范围,然后发现四个连乘之后,数据达到了10^20级别,而下面是各种数据类型的数据范围:
然后发现unsigned long long的最大值也只是10^19次方级别的数据,而四个连乘之后数据范围明显超过了unsigned long long的最大值,那么我们要怎么做才能得到正确答案呢?我们发现,连续的两个数必定有一个是偶数,连续的三个数必定有一个是3的倍数,同理,连续的四个数必定有一个是4的倍数,所以呢,我们可以不必要直接把四个含有N的表达式全部相乘,可以连续两个乘过之后,除以2,然后再乘一个,除以3,这样的话,在N取得最大值10^5的情况下,前面四个连乘后得出的结果为:16665666684999900000,数据范围在unsign long long之内,这样的话,我们解决了问题。再除以4,这样的话,所以得出以下完整代码:
#include
#include
using namespace std;
typedef unsigned long long int ull;
int main()
{
int T;
ull N;
scanf("%d",&T);
while(T--)
{
scanf("%I64u",&N);
ull sum = N;
if(N>3)
sum += N * (N - 1) / 2 * (N - 2) / 3 * (N - 3) / 4; //ULL只有19位
printf("%I64u\n",sum);
}
return 0;
}