[2019.3.4]BZOJ1213 [HNOI2004]高精度開根
阿新 • • 發佈:2019-03-17
har ++i 二分答案 pytho operator sin ons class 比較
首先你需要一個python高精度模板。
然後二分答案,快速冪判斷就好了。
設被開根數\(n\)有\(b\)位。
發現樸素的高精度乘法是\(O(b^2)\)的,所以我們考慮優化
你可以寫壓位高精(我最後的做法,壓了8位),或者寫一個FFT。
提示:最好不要嘗試同時壓8位+FFT,否則你就會像我一樣因為精度問題調一晚上+一下午並且最終放棄QWQ
有一個小優化,由於一個\(b\)位數開\(m\)次根的位數不會超過\(\lfloor\frac{b}{m}\rfloor+1\),所以二分上界可以設為\(\lfloor\frac{b}{m}\rfloor+1\)個9,在\(m\)比較大的時候得到比較好的優化效果。
加優化時間復雜度\(O((\frac{b}{m})^2\log10^{\frac{b}{m}}\log m)\)。
code:
#include<bits/stdc++.h> using namespace std; const long long base=1e9; int la,lb,s,lc; struct NUM{ long long v[2000]; int sz; void operator~(){ memset(v,0,sizeof(v)); } NUM operator+(const NUM&y)const{ NUM tmp; ~tmp; long long w=0; tmp.sz=max(sz,y.sz); for(int i=1;i<=tmp.sz;++i)tmp.v[i]=v[i]+y.v[i]+w,w=tmp.v[i]/base,tmp.v[i]%=base,w&&i==tmp.sz?++tmp.sz:0; return tmp; } NUM operator*(const NUM&y)const{ NUM tmp; ~tmp; long long w=0; tmp.sz=sz+y.sz; for(int i=1;i<=sz;++i)for(int j=1;j<=y.sz;++j)tmp.v[i+j-1]+=v[i]*y.v[j]; for(int i=1;i<=tmp.sz;++i)tmp.v[i]+=w,w=tmp.v[i]/base,tmp.v[i]%=base,w&&i==tmp.sz?++tmp.sz:0; while(!tmp.v[tmp.sz])--tmp.sz; return tmp; } NUM operator/(const int&y){ NUM tmp; ~tmp; long long w=0; if(v[sz]>=y)tmp.sz=sz; else w=v[sz]*base,tmp.sz=sz-1; for(int i=tmp.sz;i>=1;--i)w+=v[i],tmp.v[i]=w/y,w=w%y*base; return tmp; } NUM operator-(const int&y){ NUM tmp; ~tmp; tmp.sz=sz; for(int i=1;i<=sz;++i)tmp.v[i]=v[i]; tmp.v[1]-=y; int nw=1; while(tmp.v[nw]<0)tmp.v[nw]+=base,--tmp.v[++nw]; if(tmp.sz!=0&&!tmp.v[tmp.sz])--tmp.sz; return tmp; } NUM operator+(const int&y){ NUM tmp; ~tmp; tmp.sz=sz; for(int i=1;i<=sz;++i)tmp.v[i]=v[i]; tmp.v[1]+=y; int nw=1; while(tmp.v[nw]>=base)tmp.v[nw]-=base,++tmp.v[++nw]; if(tmp.v[tmp.sz+1])++tmp.sz; return tmp; } bool operator>(const NUM&y)const{ if(sz!=y.sz)return sz>y.sz; for(int i=sz;i>=1;--i)if(v[i]!=y.v[i])return v[i]>y.v[i]; return false; } bool operator<(const NUM&y)const{ if(sz!=y.sz)return sz<y.sz; for(int i=sz;i>=1;--i)if(v[i]!=y.v[i])return v[i]<y.v[i]; return false; } }N,L,R,MID; int n,m,nw,bs; char tmp[10010]; void scan(NUM &x){ scanf("%s",tmp+1); n=strlen(tmp+1),nw=n+1; while(nw>1){ ++x.sz,bs=1; while(nw>1&&bs<base)x.v[x.sz]+=(tmp[--nw]-'0')*bs,bs*=10; } } void print(NUM x){ if(!x.sz)putchar('0'); else{ for(int i=x.sz,p0=base/10;i>=1;--i,p0=base/10){ if(i!=x.sz)while(x.v[i]<p0)putchar('0'),p0/=10; if(p0)printf("%d",x.v[i]); } } } NUM POW(NUM x,int y){ NUM tot; tot.sz=tot.v[1]=1; while(y)y&1?tot=tot*x,0:0,x=x*x,y>>=1; return tot; } int tt=0; int main(){ scanf("%d",&m); scan(N); L.sz=0,n=n/m+1,nw=0; while(nw<n){ ++R.sz,bs=1; while(nw<n&&bs<base)R.v[R.sz]+=9*bs,bs*=10,++nw; } while(L<R){ MID=(L+R+1)/2; if(POW(MID,m)>N)R=MID-1; else L=MID; } print(L); return 0; }
[2019.3.4]BZOJ1213 [HNOI2004]高精度開根