SGU111 高精度開方

他們大神說這道題要什麼手工開方

我想說,什麼高端方法都弱爆了!

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

下面上我的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();
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章