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;
}