SGU111 高精度开方

10 篇文章 0 订阅

他们大神说这道题要什么手工开方

我想说,什么高端方法都弱爆了!

压位高精度+二分答案大法好

下面上我的2B代码

本来我没有压位的呢,结果发现不压位会TLE

然后我就压了5位,结果乘法爆int了

然后我就果断开longlong压7位(不敢压8位的蒟蒻)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define L 10000000
#define SIZE 1500 
/*
暴力开方:高精度开方X
我会说2011普及组小孩都会这个! 
哎呀 普通二分过不了惹
压位大法好!!
egawnelkgnaweroibaweriognaweirgbawerohnawerhawenkhoweWHZrabhio
*/
typedef struct node
{
  int len;
  long long num[SIZE];
}big;
char s[SIZE]={0};
big target;
//len表示大整数的位数,num[i]--表示第i低位如 num[1]--个位
void open()
{
  freopen("111.in","r",stdin);
  freopen("111.out","w",stdout);
}
void close()
{
  fclose(stdin);
  fclose(stdout);
}
big times(big a,big b)
//计算两数之积 
{
  int i,j;
  big ans;
  memset(ans.num,0,sizeof(ans.num));
  /*相乘*/
  for (i=1;i<=a.len;i++)
    for (j=1;j<=b.len;j++)
      ans.num[i+j-1]+=a.num[i]*b.num[j];
  /*进位*/
  for (i=1;i<=a.len+b.len;i++)
  {
    ans.num[i+1]+=ans.num[i]/L;
    ans.num[i]%=L;
    if (ans.num[a.len+b.len]>0)
      ans.len=a.len+b.len;
    else 
      ans.len=a.len+b.len-1;
  }
  return ans;
} 
big add(big a,big b)
//计算大整数a+b 
{
  int i;
  big ans;
  memset(ans.num,0,sizeof(ans.num));
  /*相加*/
  ans.len=MAX(a.len,b.len);
  for (i=1;i<=ans.len;i++)
  {
    ans.num[i]+=a.num[i]+b.num[i];
    ans.num[i+1]+=ans.num[i]/L;
    ans.num[i]%=L;
  }
  if (ans.num[ans.len+1]>0)
    ans.len++;
  return ans;
}
big ave(big a,big b)
//计算[(a+b)/2] 
{
  int i;
  big ans;
  ans=add(a,b);//先算和
  for (i=ans.len;i>=2;i--)
  {
    ans.num[i-1]+=(ans.num[i]%2)*L;
    ans.num[i]=ans.num[i]/2;
  } 
  ans.num[1]=ans.num[1]/2;
  if (ans.num[ans.len]==0)
    ans.len--;
  return ans;
}
big addd(big a,int n)
//计算大整数a+n(单精度) 
{
  int i;
  a.num[1]+=2;
  for (i=1;i<=a.len && (a.num[i])>=L;i++)
  {
    a.num[i+1]+=a.num[i]/L;
    a.num[i]%=L;
  }
  if (a.num[a.len+1]>0)
    a.len++;
  return a;
}
int da(big a,big b)
//判断a>b么 
{
  int i;
  if (a.len<b.len)
  {
    return 0;
  }
  for (i=a.len;i>=1;i--)
    if (a.num[i]!=b.num[i])
      break;
  if (a.num[i]<=b.num[i])
    return 0;
  else 
    return 1;
}
void init()
{
  int i,j,k;
  int ten[10]={0,1,10,100,1000,10000,100000,1000000,10000000};
  scanf("%s",s);
  target.len=strlen(s);
  /*
  7位一存 
  */
  for (i=target.len-1,j=1,k=1;i>=0;i--,k++)
  { 
    if (k==8)
    {
	  k=1;
	  j++;
	}
    target.num[j]+=(s[i]-'0')*ten[k];
  } 
  target.len=j;
}
void print(big a)
{
  int i;
  printf("%d",a.num[a.len]);
  for (i=a.len-1;i>=1;i--)
  {
  	if (a.num[i]<1000000) printf("0");
  	if (a.num[i]<100000) printf("0");
  	if (a.num[i]<10000) printf("0");
    if (a.num[i]<1000) printf("0");
    if (a.num[i]<100) printf("0");
    if (a.num[i]<10) printf("0");
    printf("%d",a.num[i]);
  }
  printf("\n");
}
void erfen()
{
  big left={0},right={0},middle;
  left.len=1;
  left.num[1]=1;
  right=target;
  do
  {
    middle=ave(left,right);
    //printf("mid=");print(middle);
    //printf("mid^2=");print(times(middle,middle));
    if (da(times(middle,middle),target)==0) 
	{
	  left=middle;
	}
	else 
	  right=middle;
  }
  while(da(addd(left,2),right)==0);
  /*
  for (i=left.len;i>=1;i--)
    printf("%d",left.num[i]);
  */
  print(left);
}
int main()
{
  open();
  init();
  erfen();
  close();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值