Heron and His Triangle(HDU 6222 找规律+大数)

版权声明:本文为博主原创文章,未经博主允许不得转载。若有误,欢迎私信指教~ https://blog.csdn.net/little_starfish/article/details/82015224

Heron and His Triangle(HDU 6222 找规律+大数)

Problem Description

A triangle is a Heron’s triangle if it satisfies that the side lengths of it are consecutive integers t−1, t, t+ 1 and thatits area is an integer. Now, for given n you need to find a Heron’s triangle associated with the smallest t bigger
than or equal to n.

Input

The input contains multiple test cases. The first line of a multiple input is an integer T (1 ≤ T ≤ 30000) followedby T lines. Each line contains an integer N (1 ≤ N ≤ 10^30).

Output

For each test case, output the smallest t in a line. If the Heron’s triangle required does not exist, output -1.

Sample Input

4
1
2
3
4

Sample Output

4
4
4
4

Source

2017ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)

题意

T组输入。给一个整数N (1 ≤ N ≤ 10^30). 以整数 t-1、t、t+1,三个正整数构成的三角形的面积为S
问使t>=N,的最小的 t 是多少
注:面积S要求是正整数

思路

一看可以推出三角形面积公式,所以首先要打表看看有没有规律
三角形面积S=(1/2)*a*b*sin(a,b);
cos(a,b) = (a^2+b^2-c^2)/(2*a*b) ;
sin(a,b)^2+cos(a,b)^2=1 ;
a=a; b=a+1; c=a+2; //a,b,c的关系

枚举前几项符合题意的t:4、14、52、 194、 724 …

发现规律:t【i】= t【i - 1】*4 - t【i - 2】

看规律t的增速很大,故符合题意的t的个数很少,所以找出所有的t,再暴力循环找最小即可
因为值比较大,需要用大数相乘和相减。

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
char s[40],num[222][40];
//大数的位数比较小
void mul(int id)  //大数相乘,这个函数只针对于本题的一个大数*4,不适用于两个大数相乘
{
    char res[40];
    int j,len=strlen(num[id-1]);
    num[id][len]='\0';
    int flag=0;
    for(j=len-1;j>=0;j--){  //从最低位开始加
        int val=(num[id-1][j]-'0')*4+flag;  
        num[id][j]=val%10+'0';  
        flag=val/10;  //若flag!=0,则有进位
    }
    if(flag){  //注意加到原数的最高位后还可能有新进位
        res[0]=flag+'0';
        res[1]='\0';
        strcat(res,num[id]);  //字符串链接,把num[id]接在res后面
        strcpy(num[id],res);  //把结果复制给num[id]
    }
   // printf("id:%d %s\n", id,num[id]);
}
void cub(int a,int b)  //两个大数相减 a、b分别表示两个大数的下标,不是要相减的俩个数
{
    char s[40],res[40];
    int i,j,flag=0;
    int lena=strlen(num[a]);
    int lenb=strlen(num[b]);
    res[lenb]='\0';
    j=lena-1;
    for(i=lenb-1;i>=0;i--){  //从最低位开始减
        int k=num[a][j]-num[b][i]-flag;  //flag用于表示是否有借位
        j--;
        if(k<0){   //该位置需要向上一位数字借一位
            flag=1;
            res[i]=k+10+'0';
        }
        else{
            flag=0;
            res[i]=k+'0';
        }

    }
    for(i=0;i<lena-lenb;i++){  //把被减数前面的几个高位赋值给字符串s
        s[i]=num[a][i];
    }
    if(flag){  //如果有借位
        s[lena-lenb-1]--;
    }
    s[lena-lenb]='\0';
    strcat(s,res);
    strcpy(num[a],s);
   // printf("a:%d %s\n", a,num[a]);
}
int compare(char a[],char b[])  //比较大数a与b的大小关系,若a>b返回0,否则返回1
{
    int lena=strlen(a);
    int lenb=strlen(b);
    if(lenb<lena)
        return 0;
    else if(lenb>lena)
        return 1;
    for(int i=0;i<lena;i++){  //要从最高位开始比较
        int k=b[i]-a[i];
        if(k>0)
            return 1;
        if(k<0)
            return 0;
    }
    return 1;
}
int main()
{
    int i,j,t;
    strcpy(num[0],"4");
    strcpy(num[1],"14");
    for(i=2;i<=200;i++){
        mul(i);
        cub(i,i-2);
        if(strlen(num[i])>=31){  //超过N的最大值了,所有的t已经找全了
            //printf("num:%d\n", i);
            break;
        }
    }
    //printf("%s",num[i]);
    scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        if(strcmp(s,"1")==0||strcmp(s,"2")==0||strcmp(s,"3")==0||strcmp(s,"4")==0){
            printf("4\n");
            continue;
        }
        int k,cnt;
        for(i=0;;i++){  //寻找第一个>=询问的t  
            k=compare(s,num[i]);
            if(k>0){  
                cnt=i;
                break;
            }
        }
        printf("%s\n",num[cnt]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/little_starfish/article/details/82015224
今日推荐