P2293 高精度开根

原题链接

P2293

题目描述

这是一道非常的题目:
提交记录
大概意思是:给你两个数, m ( 1 ≤ m ≤ 50 ) m(1\le m\le 50) m(1m50) n ( 1 ≤ n ≤ 1 0 10000 ) n(1\le n\le 10^{10000}) n(1n1010000),求 n m \sqrt[m]{n} mn

解题思路

这题,一看就是高精度。高精度的开根,如果上网搜,会搜索出各种玄学高级解法,但是由于太高级,我无法理解,我们可以采用一种非常朴素的写法:二分。
粗略地算了一下时间复杂度,但如果使用暴力,那么时间复杂度将会达到 O ( l o g 2 n ) O(log_{2}n) O(log2n),很好,愉快超时。
为了解决这个问题,我们需要使用一点数学优化: ⌊ l o g 10 ( ⌊ l o g 10 n ⌋ / m ) ⌋ − 1 ≤ ⌊ l o g 10 n m ⌋ ≤ ⌊ l o g 10 ( ⌊ l o g 10 n ⌋ / m ) ⌋ + 1 \lfloor log_{10}(\lfloor log_{10}n\rfloor/m)\rfloor-1 \le \lfloor log_{10}\sqrt[m]{n}\rfloor \le \lfloor log_{10}(\lfloor log_{10}n\rfloor/m)\rfloor+1 log10(⌊log10n/m)⌋1log10mn log10(⌊log10n/m)⌋+1(简单来说,就是答案的位数是根号下数的位数除以开的次方数 ± 1 \pm 1 ±1),也就是说如: ⌊ l o g 10 ( ⌊ l o g 10 100000000 ⌋ / 2 ) ⌋ − 1 ≤ ⌊ l o g 10 100000000 2 ⌋ ≤ ⌊ l o g 10 ( ⌊ l o g 10 100000000 ⌋ / 2 ) ⌋ + 1 \lfloor log_{10}(\lfloor log_{10}100000000\rfloor/2)\rfloor-1 \le \lfloor log_{10}\sqrt[2]{100000000}\rfloor \le \lfloor log_{10}(\lfloor log_{10}100000000\rfloor/2)\rfloor+1 log10(⌊log10100000000/2)⌋1log102100000000 log10(⌊log10100000000/2)⌋+1(答案是5位,在 ⌊ 9 / 2 ⌋ − 1 \lfloor 9/2\rfloor-1 9/21 ⌊ 9 / 2 ⌋ + 1 \lfloor 9/2\rfloor+1 9/2+1之间)。如此,可以将时间复杂度降低至 O ( l o g 2 1000 ) O(log_21000) O(log21000)。结果,一提交:
提交记录TLE
妙啊!还是超时,继续优化。无能为力之下,只能使用压位高精。
压位高精
c++里的高精通常都是这样的:
a:1 | 2 | 3 | 4 |
b:1 | 2 | 3 | 4 |
但是,既占空间,又占时间。我们发现,就算是使用 i n t int int,也可以,存下 0 ∼ 2147483647 0\sim 2147483647 02147483647,所以如果说这么存:
a:1234
b:1234
就OK了(时间复杂度将会降低至原来的 1 压位位 数 2 \frac 1 {压位位数^2} 压位位21)。
终于,历经千辛万苦后:
提交记录AC

代码实现

#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#include<ctime>
#include<fstream>
#include<queue>
#include<vector>
#include<stack>
#include<string>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
struct node{
	unsigned long long h_int[5000],lenth;
};
struct node2{
	node ds,ys;
};
string a;
long long n;
node jia(node jia1,node jia2)
{
	node ans;
	unsigned long long jw=0,t; 
	ans.lenth=max(jia1.lenth,jia2.lenth)+1;
	for(long long i=1;i<=4999;++i){
		t=jia1.h_int[i]+jia2.h_int[i]+jw;
		jw=t/100000000ll;
		ans.h_int[i]=t%100000000ll;
	}
	if(ans.h_int[ans.lenth]==0)
		ans.lenth--;
	return ans;
}
node jian(node jian1,node jian2)
{
	node ans;
	unsigned long long t,jw=0;
	for(long long i=1;i<=4999;i++){
		if(jian1.h_int[i]-jw>=jian2.h_int[i]){
			ans.h_int[i]=jian1.h_int[i]-jian2.h_int[i]-jw;
			jw=0;
		}
		else{
			ans.h_int[i]=100000000ll+jian1.h_int[i]-jian2.h_int[i]-jw;
			jw=1;
		}
	}
	ans.lenth=2500;
	while(ans.h_int[ans.lenth]==0&&ans.lenth>0)
		ans.lenth--;
	return ans;
} 
node cheng(node s1,node s2)
{
	node ans;
	memset(ans.h_int,0,sizeof(ans.h_int));
	ans.lenth=s1.lenth+s2.lenth;
	unsigned long long t,jw=0;
	for(long long i=1;i<=s1.lenth;++i)
		for(long long j=1;j<=s2.lenth;++j){
			t=s1.h_int[i]*s2.h_int[j]+jw;
			ans.h_int[i+j-1]+=t;
		}
	for(int i=1;i<=ans.lenth;i++){
		ans.h_int[i+1]+=ans.h_int[i]/100000000ll;
		ans.h_int[i]%=100000000ll;
	}
	if(ans.h_int[ans.lenth]==0)
		ans.lenth--;
	return ans;
}
bool q_bigger_h(node q,node h)
{
	if(q.lenth!=h.lenth) return q.lenth>h.lenth;
	for(int i=q.lenth;i>0;i--)
		if(q.h_int[i]!=h.h_int[i])
			return q.h_int[i]>h.h_int[i];
	return false;
}
node chu(node bcs)
{
	node ans;
	ans=bcs;
	for(int i=ans.lenth;i>=2;i--){
        ans.h_int[i-1]+=(ans.h_int[i]%2)*100000000ll;
        ans.h_int[i]/=2;
    }
    ans.h_int[1]/=2;
    if(ans.h_int[ans.lenth]==0)
        ans.lenth--;
    return ans;
}
node cifang(node d,unsigned long long zs)
{
	node ans,s=d;
	ans.lenth=1;
	ans.h_int[1]=1;
	while(zs!=0){
		if(zs%2==1)
			ans=cheng(ans,s);
		s=cheng(s,s);
		zs=zs/2;
	}
	return ans;
}
long long log_10(unsigned long long n){
	long long ans=0;
	while(n!=0){
		n/=10;
		ans++;
	}
	return ans;
}
unsigned long long to_n(string a)
{
	unsigned long long value=0;
	for(long long i=0;i<a.size();i++)
		value=value*10+a[i]-'0';
	return value;
}
string ycl_l(long long l)
{
	string value="1";
	for(long long i=2;i<=l;i++)
		value+="0";
	return value;
}
string ycl_r(long long l)
{
	string value="";
	for(long long i=1;i<=l;i++)
		value+="9";
	return value;
}
bool e(node q,node h)
{
	if(q.lenth!=h.lenth)
		return false;
	for(int i=1;i<5000;i++)
		if(q.h_int[i]!=h.h_int[i])
			return false;
	return true;
}
int main()
{
	ios::sync_with_stdio(false);
	node jia_1;
	jia_1.lenth=1;
	jia_1.h_int[1]=1;
	cin>>n;
	cin>>a;
	if(n==1){
		cout<<a;
		return 0;
	}
	if(a=="1"||a=="0"){
		cout<<a;
		return 0;
	}
	node a_t;
	string t="";
	a_t.lenth=0;
	int len=a.size()-1,n_len=a.size();
	memset(a_t.h_int,0,sizeof(a_t.h_int));
	while(len>6){
		t=a.substr(len-7,8);
		a_t.h_int[++a_t.lenth]=to_n(t);
		len-=8;
	}
	if(len>=0){
		t=a.substr(0,len+1);
		a_t.h_int[++a_t.lenth]=to_n(t);
	}
	string l="",r="";
	if(a.size()/n-1<=0)
		l="0";
	else
		l=ycl_l(a.size()/n-1);
	if(a.size()/n+1>a.size())
		r=a;
	else
		r=ycl_r(a.size()/n+1);
	node l_t,r_t;
	len=l.size()-1,n_len=l.size();
	memset(l_t.h_int,0,sizeof(l_t.h_int));
	l_t.lenth=0;
	while(len>6){
		t=l.substr(len-7,8);
		l_t.h_int[++l_t.lenth]=to_n(t);
		len-=8;
	}
	if(len>=0){
		t=l.substr(0,len+1);
		l_t.h_int[++l_t.lenth]=to_n(t);
	}
	len=r.size()-1,n_len=r.size();
	memset(r_t.h_int,0,sizeof(r_t.h_int));
	r_t.lenth=0;
	while(len>6){
		t=r.substr(len-7,8);
		r_t.h_int[++r_t.lenth]=to_n(t);
		len-=8;
	}
	if(len>=0){
		t=r.substr(0,len+1);
		r_t.h_int[++r_t.lenth]=to_n(t);
	}
	node mid,mid_n;
	do{
		mid=chu(jia(l_t,r_t));
		mid=jia(mid,jia_1);
		mid_n=cifang(mid,n);
		if(e(mid_n,a_t)){
			cout<<mid.h_int[mid.lenth];
			for(int i=mid.lenth-1;i>0;i--){
				if(mid.h_int[i]!=0)
					for(long long j=1;j<=8-log_10(mid.h_int[i]);j++)
						cout<<0;
				else
					cout<<"0000000"; 
				cout<<mid.h_int[i];
			}
			return 0;
		}
		if(q_bigger_h(mid_n,a_t))
			r_t=jian(mid,jia_1);
		else
			l_t=mid;
	}
	while(q_bigger_h(r_t,l_t));
	cout<<l_t.h_int[mid.lenth];
	for(int i=l_t.lenth-1;i>0;i--){
		if(l_t.h_int[i]!=0)
			for(long long j=1;j<=8-log_10(l_t.h_int[i]);j++)
				cout<<0;
		else
			cout<<"0000000";
		cout<<l_t.h_int[i];
	}
	return 0;
}

样例1

输入

3
1000000000

输出

1000

样例2

输入

2
100000000020000000001

输出

10000000001

样例3

输入

50
1

输出

1

关于坑点

压位高精的输出中,当本身就是0,只输出 压位个数 − 1 压位个数-1 压位个数1 个的0,真的被坑到了!另外,这题不开 unsigned long long 会裂开得非常惨!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值