zoukankan      html  css  js  c++  java
  • [2019.3.4]BZOJ1213 [HNOI2004]高精度开根

    首先你需要一个python高精度模板。

    然后二分答案,快速幂判断就好了。

    设被开根数(n)(b)位。

    发现朴素的高精度乘法是(O(b^2))的,所以我们考虑优化

    你可以写压位高精(我最后的做法,压了8位),或者写一个FFT。

    提示:最好不要尝试同时压8位+FFT,否则你就会像我一样因为精度问题调一晚上+一下午并且最终放弃QWQ

    有一个小优化,由于一个(b)位数开(m)次根的位数不会超过(lfloorfrac{b}{m} floor+1),所以二分上界可以设为(lfloorfrac{b}{m} floor+1)个9,在(m)比较大的时候得到比较好的优化效果。

    加优化时间复杂度(O((frac{b}{m})^2log10^{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;
    }
    
  • 相关阅读:
    Pipe
    An Easy Problem?!
    Kadj Squares
    Space Ant
    Intersection
    让网页变为可编辑状态
    typescript入门基础
    大家都能看懂的 canvas基础教程
    数组的foreach方法和jQuery中的each方法
    html单行、多行文本溢出隐藏
  • 原文地址:https://www.cnblogs.com/xryjr233/p/BZOJ1213.html
Copyright © 2011-2022 走看看