HDU5621——数学应用(多边形内对角线交点个数) + 数论 + unsigned long long的应用

题目描述:

KK's Point

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 713    Accepted Submission(s): 238


Problem Description
Our lovely KK has a difficult mathematical problem:He points  N(2N105)  points on a circle,there are all different.Now he's going to connect the  N  points with each other(There are no three lines in the circle to hand over a point.).KK wants to know how many points are there in the picture(Including the dots of boundary).
 

Input
The first line of the input file contains an integer  T(1T10) , which indicates the number of test cases.

For each test case, there are one lines,includes a integer  N(2N105) ,indicating the number of dots of the polygon.
 

Output
For each test case, there are one lines,includes a integer,indicating the number of the dots.
 

Sample Input
  
  
2 3 4
 

Sample Output
  
  
3 5
题意:

一个圆周上点下了互不重合的N(2≤N≤105)个点,将这N个点两两相连(圆内没有三条线交于一个点的情况),图形中一共有多少个交点(包括边界上的点)。

解析:

同样,这也是一道找规律的题目,将这N个点两两相连,当N>3时,在外部则形成了一个多边形,然后内部的连线则是多边形的对角线,而这道题便转换为多边形内对角线交点个数的问题,即原问题转换成数学问题:

给定一个凸N边形,满足性质:任何三条对角线都不交于同一点.在这样一个多边形的内部,它的所有对角线共形成多少个交点?

由于每一个交点对应着两条相交的对角线,而两条相交的对角线确定一个四边形,所以计算交点的个数即是计算多边形内四边形的个数,所以原问题又转换为多边形内四边形的个数,而四边形四个点,所以这就是我们熟悉的组合问题了(在N个点中任意找四个点形成一个四边形),那么交点个数=四边形个数=C(N,N-4).考虑特殊情况后,很快便得出完整代码:

#include<cstdio>
#include<algorithm>
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<cstdio>
#include<algorithm>
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<cstdio>
#include<algorithm>
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;
}

总结:这道题其实不难,考的是数学应用,但是这道题考察了平时会比较忽略的知识(unsigned long long,溢出最大数据范围等问题),所以呢,我们才一时找不出错误,这更警醒我们要注重基础,多了解一点总是没有害处的。然后平时要多积累,注意数学问题之间的转换,可以化难为易,并且转换成我们能够解决的问题。



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值