Timus 1153. Supercomputer

Timus 1153. Supercomputer 要求根据自然数列的前 N 项和求 N 值。

1153. Supercomputer

Time Limit: 2.0 second
Memory Limit: 16 MB

To check the speed of JCN Corporation new supercomputer it was decided to figure out the sum of first N (N<10 600) positive integers. Unfortunately, by the time the calculation was finished the Chief Programmer forgot the value of N he entered. Your task is to write the program (for personal computer), which would determine the value of N by the result calculated on supercomputer.

Note:
JCN Corporation manufactures only reliable computers, and its programmers write only correctly working programs.

Input

One line containing number M - the result of calculations on supercomputer.

Output

One line, containing N - number, entered by Chef Programmer.

Sample

input output
28 7
Problem Author: Eugene Bryzgalov
Problem Source: Ural Collegiate Programming Contest, April 2001, Perm, English Tour

解答如下:

  1  using  System;
  2  using  System.Globalization;
  3 
  4  namespace  Skyiv.Ben.Timus
  5  {
  6     //   http://acm.timus.ru/problem.aspx?space=1 &num=1153
  7     sealed   class  T1153
  8    {
  9       static   void  Main()
 10      {
 11        BigInteger m  =  BigInteger.Parse(Console.ReadLine());
 12        Console.WriteLine(BigInteger.Sqrt(m  +  m));
 13      }
 14    }
 15 
 16     sealed   class  BigInteger : IComparable < BigInteger >
 17    {
 18       int [] digits  =   new   int [ 601 ];
 19 
 20       public  BigInteger( int  n)
 21      {
 22        digits[ 0 =  n;
 23         if  (digits[ 0 >   9 ) Format();
 24      }
 25 
 26       public  BigInteger(BigInteger x)
 27      {
 28        Array.Copy(x.digits, digits, digits.Length);
 29      }
 30 
 31       public   static  BigInteger Parse( string  s)
 32      {
 33        BigInteger x  =   new  BigInteger( 0 );
 34         for  ( int  i  =  s.Length  -   1 ; i  >=   0 ; i -- ) x.digits[s.Length  -   1   -  i]  =  s[i]  -   ' 0 ' ;
 35         return  x;
 36      }
 37 
 38       public   int  CompareTo(BigInteger x)
 39      {
 40         for  ( int  i  =  digits.Length  -   1 ; i  >=   0 ; i -- )
 41        {
 42           if  (digits[i]  >  x.digits[i])  return   1 ;
 43           else   if  (digits[i]  <  x.digits[i])  return   - 1 ;
 44        }
 45         return   0 ;
 46      }
 47 
 48       public   static  BigInteger Sqrt(BigInteger x)
 49      {
 50        BigInteger low, high;
 51        GetLowAndHigh(x,  out  low,  out  high);
 52        BigInteger mid  =  low;
 53         int  cmp  =   0 ;
 54         while  (low.CompareTo(high)  <=   0 )
 55        {
 56          mid  =  (low  +  high)  /   2 ;
 57          cmp  =  (mid  *  mid).CompareTo(x);
 58           if  (cmp  <   0 ) low  =  mid  +   1 ;
 59           else   if  (cmp  >   0 ) high  =  mid  +  ( - 1 );
 60           else   return  mid;
 61        }
 62         if  (cmp  >   0 ) mid  =  mid  +  ( - 1 );
 63         return  mid;
 64      }
 65 
 66       static   void  GetLowAndHigh(BigInteger x,  out  BigInteger low,  out  BigInteger high)
 67      {
 68         int  xmax  =  x.digits.Length  -   1 ;
 69         while  (xmax  >=   0   &&  x.digits[xmax]  ==   0 ) xmax -- ;
 70         const   int  doublePrecison  =   15 ;
 71         if  (xmax  <  doublePrecison)
 72        {
 73          low  =  high  =   new  BigInteger(( int )Math.Sqrt(GetPrefix(x, xmax, doublePrecison)));
 74           return ;
 75        }
 76         int  zeros  =  xmax  -  doublePrecison  +   1 ;
 77         if  (zeros  %   2   !=   0 ) zeros ++ ;
 78         string [] ss  =  Math.Sqrt(GetPrefix(x, xmax, xmax  -  zeros  +   1 )).ToString( " F8 " , CultureInfo.InvariantCulture).Split( ' . ' );
 79        low  =   new  BigInteger( 0 );
 80        zeros  /=   2 ;
 81         int  j  =   1 ;
 82         for  ( int  i  =   0 ; i  <  ss[ 0 ].Length; i ++ ) low.digits[i  +  zeros]  =  ss[ 0 ][ss[ 0 ].Length  -   1   -  i]  -   ' 0 ' ;
 83         for  ( int  i  =   0 ; i  <  ss[ 1 ].Length  -   2   &&  j  <=  zeros; i ++ , j ++ ) low.digits[zeros  -  j]  =  ss[ 1 ][i]  -   ' 0 ' ;
 84        high  =   new  BigInteger(low);
 85         if  ( ++ high.digits[zeros  -  j  +   1 >   9 ) high.Format();
 86      }
 87 
 88       static   long  GetPrefix(BigInteger x,  int  start,  int  length)
 89      {
 90         long  v  =   0 ;
 91         for  ( int  i  =  start; i  >=   0   &&  length  >   0 ; i -- , length -- ) v  =  v  *   10   +  x.digits[i];
 92         return  v;
 93      }
 94 
 95       public   static  BigInteger  operator   + (BigInteger x,  int  y)
 96      {
 97        BigInteger z  =   new  BigInteger(x);
 98        z.digits[ 0 +=  y;
 99         if  (z.digits[ 0 >   9   ||  z.digits[ 0 <   0 ) z.Format();
100         return  z;
101      }
102 
103       public   static  BigInteger  operator   + (BigInteger x, BigInteger y)
104      {
105        BigInteger z  =   new  BigInteger(x);
106         for  ( int  i  =  x.digits.Length  -   1 ; i  >=   0 ; i -- ) z.digits[i]  =  x.digits[i]  +  y.digits[i];
107        z.Format();
108         return  z;
109      }
110 
111       public   static  BigInteger  operator   * (BigInteger x, BigInteger y)
112      {
113        BigInteger z  =   new  BigInteger( 0 );
114         int  xmax  =  x.digits.Length  -   1 ;
115         int  ymax  =  y.digits.Length  -   1 ;
116         while  (xmax  >=   0   &&  x.digits[xmax]  ==   0 ) xmax -- ;
117         while  (ymax  >=   0   &&  y.digits[ymax]  ==   0 ) ymax -- ;
118         for  ( int  xi  =  xmax; xi  >=   0 ; xi -- )
119           for  ( int  yi  =  ymax; yi  >=   0 ; yi -- )
120            z.digits[xi  +  yi]  +=  x.digits[xi]  *  y.digits[yi];
121        z.Format();
122         return  z;
123      }
124 
125       public   static  BigInteger  operator   / (BigInteger x,  int  y)
126      {
127        BigInteger z  =   new  BigInteger( 0 );
128         int  xmax  =  x.digits.Length  -   1 ;
129         while  (xmax  >=   0   &&  x.digits[xmax]  ==   0 ) xmax -- ;
130         for  ( int  remainder  =   0 , i  =  xmax; i  >=   0 ; i -- )
131        {
132           int  quotient  =   10   *  remainder  +  x.digits[i];
133          remainder  =  quotient  %  y;
134          z.digits[i]  =  quotient  /  y;
135        }
136         return  z;
137      }
138 
139       void  Format()
140      {
141         for  ( int  quotient  =   0 , i  =   0 ; i  <  digits.Length; i ++ )
142        {
143           int  numerator  =  digits[i]  +  quotient;
144          quotient  =  numerator  /   10 ;
145           int  remainder  =  numerator  %   10 ;
146           if  (remainder  <   0 )
147          {
148            remainder  +=   10 ;
149            quotient -- ;
150          }
151          digits[i]  =  remainder;
152        }
153      }
154 
155       public   override   string  ToString()
156      {
157         int  n  =  digits.Length  -   1 ;
158         while  (n  >=   0   &&  digits[n]  ==   0 ) n -- ;
159         if  (n  <   0 return   " 0 " ;
160         char [] cs  =   new   char [n  +   1 ];
161         for  ( int  i  =  n; i  >=   0 ; i -- ) cs[i]  =  ( char )(digits[n  -  i]  +   ' 0 ' );
162         return   new   string (cs);
163      }
164    }
165  }

我们知道,自然数列的前 N 项和 M = N * ( N + 1 ) / 2 ≈ N2 / 2。所以 N = [ √ 2 * M  ]。这里 [x] 表示对 x 进行下取整。

这个程序的关键就是求 BigInteger 的平方根。本程序中第 66 到 86 行的 GetLowAndHigh() 方法估算出平方根的范围,然后在第 48 到 64 行的 Sqrt() 方法中用二分查找法找出所求的平方根。

你可能感兴趣的:(super)