HDU6217 BBP Formula

简略题意:问π的十六进制表示的小数点后第n位是多少。

关于BBP公式详见WIKI百科

这个公式的作用就是计算十六进制下的小数点后第n位,而不必计算前n-1项。
π=k=0[116k(48k+1)(28k+4)(18k+5)(18k+6)]
抽取第一个求和部分。
k=0116k(48k+1)
= k=0(416k(8k+1))
= 4 k=0(116k(8k+1))

k=0(116k(8k+1)) ,我们想要获取第n位,把原式子拆成两部分。
k=0(116k(8k+1))
= nk=0(116k(8k+1))+k=n+1(116k(8k+1))
将等式乘上 16n ,使得小数点恰好落在第n位。
nk=0(116k(8k+1))+k=n+1(116k(8k+1)) = nk=0(16nk(8k+1))+k=n+1(16nk(8k+1))
我们只关心上式的小数部分,为了避免高精度计算, nk=0(16nk(8k+1)) = nk=0(16nkmod(8k+1)(8k+1)) ,两者的小数部分是相同的,并且对于后半部分, k=n+1(16nk(8k+1)) ,这部分对精度要求并不高,我们向后处理一个足够多的位数就够了。
1=nk=0(16nk(8k+1))+k=n+1(16nk(8k+1)) , 那么答案就是 412234 的小数部分,乘以16之后,得到的整数部分转化成16进制即可。
复杂度为 O(nlogn)

#define others
#ifdef poj
#include 
#include 
#include 
#include 
#include 
#include 
#endif // poj
#ifdef others
#include 
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double eps = 1e-8;
int dcmp(double x) { if(fabs(x)<=eps) return 0; return (x>0)?1:-1;};
typedef long long LL;
typedef unsigned long long ULL;

namespace solver {
    char out(int x) {
        if(0 <= x && x <= 9) return x + '0';
        else if(x == 10) return 'A';
        else if(x == 11) return 'B';
        else if(x == 12) return 'C';
        else if(x == 13) return 'D';
        else if(x == 14) return 'E';
        else if(x == 15) return 'F';
    }
    LL Pow(LL a, LL b, LL mod) {
        LL res = 1;
        while(b) {
            if(b & 1) res *= a, res %= mod;
            b >>= 1;
            a *= a, a %= mod;
        }
        return res;
    }
    double BBP(int n, LL k, LL b) {
        double val = 0;
        for(int i = 0; i <= n; i++)  val += (Pow(16, n-i, 8*i+b)*1.0/(8*i+b));
        for(int i = n + 1; i <= n + 1 + 1000; i++) val += (powf(16, n - i)/(8*i+b));
        return k*val;
    }
    void solve() {
        int t;
        scanf("%d", &t);
        int f = 0;
        while(t--) {
            double v = 0;
            int n;
            scanf("%d", &n);
            n--;
            v = BBP(n, 4, 1) + BBP(n, -2, 4) + BBP(n, -1, 5) + BBP(n, -1, 6);
            v = v - (int)v;
            if(v < 0) v += 1;
            v *= 16;
            printf("Case #%d: %d %c\n", ++f, n + 1, out((int)v));
        }
    }
}

int main() {
    solver::solve();
    return 0;
}

你可能感兴趣的:(数学)