银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::
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<10600) 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

inputoutput
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 < 0return "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() 方法中用二分查找法找出所求的平方根。

posted on 2008-06-24 23:29  银河  阅读(939)  评论(0编辑  收藏  举报