P2293 [HNOI2004]高精度开根

思路很简单

由于高精度开根十分难搞

所以考虑逆向思路

二分答案 然后利用\(mid^m\)同原始数据进行比较

但是由于这其中涉及到了乘法而且高精度乘法是\(n^2\)级别的

肿么办???一开始想到了FFT但是后来果断放弃了

可以考虑压位高精度

就是把10进制转化为1e8或者1e9进制

注:1.为了卡常 数组开的尽量小

2.为了防止RE 二分答案先判断数位

3.二分答案的答案初始化为原始数据 否则会WA一个点(就是存在开一次方根)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define M 1008611
#define ll long long
using namespace std;
template<typename T>void read(T &a)
{
    T x=0,f=1;char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')f=0;ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
    }
    a=f?x:-x;
}
struct Node
{
	ll num[20086];int len;
	friend bool operator <=(const Node &A,const Node &B)
	{
//		printf("左长度 is %d\n",A.len);
//		printf("右长度 is %d\n",B.len);
		if(A.len!=B.len) return A.len<B.len;
		else
		{
			for(int i=A.len;i;--i)			
			if(A.num[i]!=B.num[i]) return A.num[i]<B.num[i];
			return 1;		
		}
		
	}
	friend Node operator +(const Node &A,const Node &B)
	{
		Node tmp;memset(tmp.num,0,sizeof tmp.num);tmp.len=1;
		for(;tmp.len<=A.len||tmp.len<=B.len;++tmp.len)
		{
			tmp.num[tmp.len]+=A.num[tmp.len]+B.num[tmp.len];
			tmp.num[tmp.len+1]+=tmp.num[tmp.len]/100000000;
			tmp.num[tmp.len]%=100000000;
		}
		while(tmp.num[tmp.len+1]) ++tmp.len;
		while(!tmp.num[tmp.len] && tmp.len>1) --tmp.len;
		return tmp;
	}
	friend Node operator /(const Node &A,const int &B)
	{
		Node tmp;tmp.len=1;memset(tmp.num,0,sizeof tmp.num);
		ll now=0;
		for(int i=A.len;i;--i)
		{
			now=now*100000000+A.num[i];tmp.num[i]=now/B;now%=B;
			if(tmp.num[i]) tmp.len=max(tmp.len,i);
		}
		while(tmp.num[tmp.len+1]) tmp.len++;			
		while(!tmp.num[tmp.len]&&tmp.len>1) tmp.len--;
		return tmp;		
	}	
	friend Node operator *(const Node &A,const Node &B)
	{
		Node tmp;memset(tmp.num,0,sizeof tmp.num);tmp.len=1;
		for(int i=1;i<=A.len;++i)
		{
			ll x=0;
			for(int j=1;j<=B.len;++j)
			{
				tmp.num[i+j-1]+=A.num[i]*B.num[j]+x;
				x=tmp.num[i+j-1]/100000000;
				tmp.num[i+j-1]%=100000000;
			}
			tmp.num[i+B.len]=x;
		}
		tmp.len=A.len+B.len;
		while(tmp.num[tmp.len+1]) ++tmp.len;
		while(!tmp.num[tmp.len] && tmp.len>1) --tmp.len;
//		printf("now tmp len is %d\n",tmp.len);
		return tmp; 
	}
	friend Node operator +(const Node &A,const int &B)
	{
		Node tmp;tmp.len=1;memset(tmp.num,0,sizeof tmp.num);tmp=A;
		tmp.num[1]+=B;int now=1;
		while(tmp.num[now]>100000000) tmp.num[now+1]+=tmp.num[now]/100000000,tmp.num[now++]%=100000000;
		while(tmp.num[tmp.len+1]) tmp.len++;			
		while(!tmp.num[tmp.len]&&tmp.len>1) tmp.len--;
		return tmp;			
	}
	friend Node operator -(const Node &A,const int &B)
	{
		Node tmp;tmp.len=1;memset(tmp.num,0,sizeof tmp.num);tmp=A;
		tmp.num[1]-=B;int now=1;
		while(tmp.num[now]<0) tmp.num[now+1]--,tmp.num[now++]+=100000000;
		while(tmp.num[tmp.len+1]) tmp.len++;			
		while(!tmp.num[tmp.len]&&tmp.len>1) tmp.len--;
		return tmp;			
	}	
}cdy,wzy,le,ri,mid,ans; 
char sa[20086];
int lena,m;
void print(Node now)
{
//	printf("len is %d\n",now.len);
	for(int i=now.len;i;--i)
	{
		if(i==now.len) printf("%lld",now.num[i]);
		else
		{
			int tmp=now.num[i],have=10000000;
			while(have)
			{
				printf("%lld",tmp/have);
				tmp%=have;have/=10;
			}
			
		}
	}
	cout<<endl;
}
inline Node qpow(Node A,int B)
{
	Node res;res.len=1;memset(res.num,0,sizeof res.num);res.num[1]=1;
	for(;B;B>>=1,A=A*A)
	{		
		if(B&1) res=res*A;
//		printf("now %d\n",B);
//		printf("now res is ");print(res);
//		printf("now A is ");print(A);
	} 
	return res;
}
signed main()
{
	read(m);scanf("%s",sa+1);
	lena=strlen(sa+1);
	for(int i=lena,res=0,tmp=0,now=1;i;--i)
	{
		++res;tmp+=(sa[i]-'0')*now;now*=10;
		if(res==8 || i==1) cdy.num[++cdy.len]=tmp,tmp=res=0,now=1;
	}
//	print(cdy);
//	ans=qpow(cdy,m); 
	le.len=1;le.num[1]=1;
	ri=cdy;ans=cdy;
	while(le<=ri)
	{
//		printf("NIuBI\n");
//		print(le);printf(" ");print(ri);
//		printf("原始始 is");print(le+ri);
		mid=(le+ri)/2;
//		printf("原始 is");print(mid);
//		printf("结果 is");print(qpow(mid,m));
//		printf("比较 is");print(cdy);
		if(mid.len*m-m+1<=cdy.len && qpow(mid,m)<=cdy) ans=mid,le=mid+1;
		else ri=mid-1; 
//		printf("现在左边界是");print(le);
//		printf("现在右边界是");print(ri);
	}
	print(ans);
	return 0;
} 

这是正式退役以来发的第一篇正经博客

posted @ 2020-07-18 16:20  tcswuzb  阅读(303)  评论(0编辑  收藏  举报