zoukankan      html  css  js  c++  java
  • UVALive8201BBP Formula

    8201-BBP Formula

    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 }
    View Code
  • 相关阅读:
    web api 设置允许跨域,并设置预检请求时间
    T4模板
    DDD模式
    Vue watch用法
    第三章--第五节:集合
    简单的Python API爬虫与数据分析教程--目录
    第三章--第四节:字典
    第三章--第三节(补充):列表排序
    汇总张小龙在知乎上的问答
    第三章--第三节:列表
  • 原文地址:https://www.cnblogs.com/BlueHeart0621/p/11812773.html
Copyright © 2011-2022 走看看