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;
}
这是正式退役以来发的第一篇正经博客