/* PI Calculator Author: stdafx */ # define fastcall __attribute__((optimize("-O3"))) # define IL __inline__ __attribute__((always_inline)) # define rep(_i,_s,_t) for(register int (_i)=(_s);(_i)<=(_t);++(_i)) # define dwn(_i,_s,_t) for(register int (_i)=(_s);(_i)>=(_t);--(_i)) # include <time.h> # include <math.h> # include <string> # include <stdio.h> # include <stdlib.h> # include <assert.h> # include <iostream> # include <string.h> # include <algorithm> # define int_log 31ll # define max_used_len 2097152ll fastcall IL int intSign(long long x) { return x<0; } fastcall IL double global_time() { return (double)clock() / CLOCKS_PER_SEC; } fastcall IL int rand32() { return (int)( (rand() & 0xf) << 0 | (rand() & 0xf) << 8 | (rand() & 0xf) << 16 | (rand() & 0xf) << 24 ) % 1000000000; } fastcall IL std::string number_to_string(long long number) { char c_str[30]; sprintf(c_str,"%lld",number); std::string str = c_str; return str; } typedef double ld; int bin[int_log+1]; struct pdd { int a,b,c; }; struct cpx { ld r, i; fastcall IL cpx conj() { return (cpx){r,-i}; } }; cpx *tf1,*tf2; fastcall cpx operator + (const cpx &a, const cpx &b) { return (cpx) { a.r + b.r, a.i + b.i}; } fastcall cpx operator - (const cpx &a, const cpx &b) { return (cpx) { a.r - b.r, a.i - b.i}; } fastcall cpx operator * (const cpx &a, const cpx &b) { return (cpx) { a.r*b.r - a.i*b.i, a.r*b.i + a.i*b.r}; } fastcall cpx rand_cpx() { return (cpx){ (double)(rand32()%1000), (double)(rand32()%1000) }; } const ld eps=1e-9; void write_in_file(const char *name ,const std::string &str){ FILE *file = fopen(name, "wb"); fwrite(str.c_str(), 1, str.size(), file); fclose(file); return; } namespace FFT { # define max_fft_log 23ll # define max_fft_len 8388608ll # define M_PI 3.14159265358979323846 int *rev[max_fft_log+1]; cpx *prw[max_fft_log+1],*prwi[max_fft_log+1]; bool prepared_Rev[max_fft_log+1],prepared_W[max_fft_log+1]; void prepareRev(int lg) { register int *tmp,len=bin[lg]; rev[lg] = new int [len]; tmp=rev[lg]; tmp[0]=0; for(register int i=0;i<len;i++) tmp[i]=tmp[i>>1]>>1|((i&1)<<(lg-1)); prepared_Rev[lg]=true; return; } void prepareWn(int lg,int p) { register cpx *pw,*pwi; prw [lg] = new cpx [p]; pw = prw [lg]; prwi [lg] = new cpx [p]; pwi = prwi [lg]; register ld omega = M_PI/p,s,c; for(register int i=0;i<p;i++) { pw [i] = (cpx){ c = cos(omega*i) , s = sin(omega*i) }; pwi [i] = (cpx){ c , - s }; } prepared_W[lg] = true; return; } void fft_normal(cpx *a,int n, int flag) { // to compare for (int i = 0, j = 0; i < n; i++) { if (i > j) std::swap(a[i], a[j]); for (int t = n >> 1; (j ^= t) < t; t >>= 1); } int m = 2; cpx wn, w, t, u; for (; m <= n; m <<= 1) { wn = (cpx) {cos(2.0 * M_PI / m), flag * sin(2.0 * M_PI / m)}, w = (cpx) {1, 0}; for (int i = 0; i < n; i += m, w = (cpx) {1, 0}) for (int k = 0, p = m >> 1; k < p; ++k, w = w * wn) t = w * a[i + k + p], u = a[i + k], a[i + k] = u + t, a[i + k + p] = u - t; } if (flag == -1) for (int i = 0; i < n; i++) a[i].r /= n; return; } void fft(register cpx *f,register int lg) { register int n= 1 << lg ; if(!prepared_Rev[lg]) prepareRev(lg); register int *tRev=rev[lg],i,m,log_m,k,p; register cpx *w,*f1,*f2,t; for(i=0;i<n;++i,++tRev) if(i<*tRev) std::swap(f[i],f[*tRev]); for(m=2,log_m=1;m<=n;m<<=1,++log_m) { p=m>>1; if(!prepared_W[log_m]) prepareWn(log_m,p); for(i=0;i<n;i+=m) { w=prw[log_m]; f1=f+i,f2=f+i+p; for(k=0;k<p;++k) { t=(*w)*(*f2); (*f2)=(*f1)-t; f1->r+=t.r; f1->i+=t.i; ++f1,++f2,++w; } } } return; } void ifft(register cpx *f,register int lg) { register int n= 1 << lg ; register int *tRev=rev[lg],i,m,log_m,k,p; register cpx *w,*f1,*f2,t; for(i=0;i<n;++i,++tRev) if(i<*tRev) std::swap(f[i],f[*tRev]); for(m=2,log_m=1;m<=n;m<<=1,++log_m) { p=m>>1; for(i=0;i<n;i+=m) { w=prwi[log_m]; f1=f+i,f2=f+i+p; for(k=0;k<p;++k) { t=(*w)*(*f2); (*f2)=(*f1)-t; f1->r+=t.r; f1->i+=t.i; ++f1,++f2,++w; } } } register ld img = 1.0 / n; for(i=0;i<n;i++) f[i].r*=img; return; } void Test() { double time_tot=0; register cpx *array = new cpx [max_fft_len]; register ld *rp = new double [max_fft_len]; for(int i=0;i<=max_fft_log;i++) { int len= 1 << i ; for(int j=0;j<len;j++) array[j]=(cpx) { rp[j] = (double)(rand32()%1000), 0 }; double st=global_time(); fft(array,i); ifft(array,i); printf("time used = %.3lf ",global_time()-st); time_tot+=global_time()-st; for(int j=0;j<len;j++) assert( fabs(rp[j]-array[j].r) < eps); printf("accepted on len %d ",len); } delete []array; printf("total time used = %.3lf ",time_tot); return; } } # define EXTRA_PR 2 struct __float256 { int *array; // digits , 9 digits in one position int exp,L; // exp , total digits | if number = 0 , L = 0 bool sign; /* if sign = true , number >= 0 sign = false , number < 0 */ inline __float256() { // Initialization , 0 array = NULL; exp=L=0; sign=true; return; } fastcall IL void apply_memory(int len) { assert(array==NULL); array = new int [len]; memset(array,0,sizeof(int)*len); return; } fastcall IL void destroy() { if(array!=NULL) delete []array; array = NULL; exp=L=0; sign=true; return; } fastcall IL void set32(int number) { // 0 -> 10^9 - 1 destroy(); if(!number) return; L = 1 , apply_memory(1); if(number<0) sign=false,number=-number; else sign=true; array[0]=number; return; } fastcall IL void negate() { if(!L) return; sign^=1; return; } fastcall IL int at(int mag) { // word at (10 ^ 9) ^ mag if(mag<exp) return 0; if(mag>=L+exp) return 0; return array[ mag - exp ]; } int to_string_trimmed(int digits , std::string &str) { if(!L) { str="0"; return 0; } int exponent = exp; int length = L , *ptr = array ; if(!digits) { // all digits = length * 9; } else { int words = (digits + 17) / 9; if (words < length){ int chop = length - words; exponent += chop; length = words; ptr += chop; } } exponent *= 9; char buffer[10]; str.clear(); int c=length; while(c-- > 0) { register int word = ptr[c]; for(register int i=8;~i;--i) { buffer[i]=word%10+'0'; word/=10; } buffer[9]='