Time limit: 3.000 seconds
In 1995, Simon Plouffe discovered a special summation style for some constants. Two year later, together with the paper of Bailey and Borwien published, this summation style was named as the Bailey-Borwein-Plouffe formula.Meanwhile a sensational formula appeared. That is
π = ∑k=0∞ 16-k (4/(8*k + 1) − 2/(8*k + 4) − 1/(8*k + 5) − 1/(8*k + 6))
For centuries it had been assumed that there was no way to compute the n-th digit of π without calculating allof the preceding n − 1 digits, but the discovery of this formula laid out the possibility. This problem asks you to calculate the hexadecimal digit n of π immediately after the hexadecimal point. For example, the hexadecimalformat of n is 3.243F6A8885A308D313198A2E... and the 1-st digit is 2, the 11-th one is A and the 15-th one is D.
Input
The first line of input contains an integer T (1 ≤ T ≤ 32) which is the total number of test cases. Each of the following lines contains an integer n (1 ≤ n ≤ 100000).
Output
For each test case, output a single line beginning with the sign of the test case. Then output the integer n, and the answer which should be a character in {0, 1, ... , 9, A, B, C, D, E, F} as a hexadecimal number
Sample Input |
5 1 11 111 1111 11111 |
Sample Output |
Case #1: 1 2 Case #2: 11 A Case #3: 111 D Case #4: 1111 A Case #5: 11111 E |
题解
对于一个十进制小数x,要想获取其第n位的十六进制小数,只需先将x转为十六进制后再将小数点右移n位,则小数点左边第一个整数位对应的数字即为答案。但由于n很大,直接计算显然不行,精度不够,那该怎么办呢?事实上,如果要我们求x的第n位十进制小数,我们直接将x乘以10,即将x小数点右移了n位。对于十六进制,同理,只需将x乘以16,即将十六进制下x的小数点右移了n位。主要思想有了,我们就可以解这道题了。
对于公式π = ∑k=0∞ 16-k (4/(8*k + 1) − 2/(8*k + 4) − 1/(8*k + 5) − 1/(8*k + 6)),我们可以转化为π = 4∑1 - 2∑2 - ∑3 - ∑4,其中
∑1 = ∑k=0∞ 16-k/(8*k + 1)
∑2 = ∑k=0∞ 16-k/(8*k + 4)
∑3 = ∑k=0∞ 16-k/(8*k + 5)
∑4 = ∑k=0∞ 16-k/(8*k + 6)
我们取∑1分析,其他三个同理。对于∑1,由于我们要求的是第n位小数数字,故我们先将小数点右移n-1位,即
∑1 = ∑k=0n-1 16n-1-k/(8*k + 1) + ∑k=n∞ 16n-1-k/(8*k + 1)
由前面分析知,整数部分对最终答案没有影响,故可以通过取模去除整数部分,保留小数部分。
∑1 = ∑k=0n-1 [16n-1-k mod (8*k + 1)] / (8*k + 1) + ∑k=n∞ 16n-1-k/(8*k + 1)
∑1的前半部分通过快速幂很容易实现;而由级数的知识可以知道,∑1的后半部分会收敛到一个常数,即随着k的增大,对应的项则越来越趋于0。故∞可以取为一个稍大的数,比如500之类的。
1 #include <bits/stdc++.h> 2 #include <cstring> 3 #include <cstdio> 4 #include <cmath> 5 #include <algorithm> 6 #define re register 7 #define il inline 8 #define ll long long 9 #define ld long double 10 using namespace std; 11 const ll MAXN = 1e2+5; 12 const ll TABLE = 26; 13 const ld INF = 1e9; 14 const ld EPS = 1e-9; 15 16 //快速幂模 17 ll powmod(ll a, ll n, ll md) 18 { 19 ll ans = 1; 20 while(n) 21 { 22 if(n&1) 23 { 24 ans = (ans*a)%md; 25 } 26 a = (a*a)%md; 27 n >>= 1; 28 } 29 return ans; 30 } 31 32 //BBP Formula 33 ll BBP(ll n) 34 { 35 ld ans = 0; 36 ld ans1 = 0, ans2 = 0, ans3 = 0, ans4 = 0; 37 for(re ll i = 0; i < n; ++i) 38 { 39 ll k = n-1-i; 40 ll a = 8*i+1; 41 ll b = a + 3; 42 ll c = a + 4; 43 ll d = a + 5; 44 /* 45 //最好用这种(先算总和,最后作加减,以免产生截断误差。 46 ans1 += powmod(16,k,a)/(ld)a; 47 ans2 += powmod(16,k,b)/(ld)b; 48 ans3 += powmod(16,k,c)/(ld)c; 49 ans4 += powmod(16,k,d)/(ld)d; 50 */ 51 ans += 4*powmod(16,k,a)/(ld)a-2*powmod(16,k,b)/(ld)b-powmod(16,k,c)/(ld)c-powmod(16,k,d)/(ld)d; 52 } 53 for(re ll i = n; i <= n+10; ++i) 54 { 55 ll k = n-1-i; 56 ll a = 8*i+1; 57 ll b = a + 3; 58 ll c = a + 4; 59 ll d = a + 5; 60 /* 61 //最好用这种(先算总和,最后作加减,以免产生截断误差。 62 ans1 += powl(16,k)/a; 63 ans2 += powl(16,k)/b; 64 ans3 += powl(16,k)/c; 65 ans4 += powl(16,k)/d; 66 */ 67 ans += 4.0*powl(16.0,(ld)k)/a-2.0*powl(16.0,(ld)k)/b-1.0*powl(16.0,(ld)k)/c-1.0*powl(16.0,(ld)k)/d; 68 } 69 //最好用这种(先算总和,最后作加减,以免产生截断误差。 70 //ld ans = 4*ans1 - (2*ans2 + ans3 + ans4); 71 ans -= (ll)ans; 72 ans = ans < 0 ? ans+1 : ans; 73 return ((ll)(ans*16))%16; 74 } 75 76 //这题推荐用scanf和printf 77 //cin和cout出现玄学错误 78 //具体原因等找到再作说明 79 int main() 80 { 81 ios::sync_with_stdio(false); 82 int T; 83 //scanf("%d", T); 84 cin >> T; 85 for(re int i = 1; i <= T; ++i) 86 { 87 int n; 88 //scanf("%d", &n); 89 cin >> n; 90 ll ans = BBP(n); 91 cout << "Case #" << dec << i << ": " << dec << n << " "; 92 cout << setiosflags(ios::uppercase) << hex << ans << endl; 93 //printf("Case #%d: %d %c\n", i, n, out(ans)); 94 } 95 return 0; 96 }