Codeforces 986D Perfect Encoding FFT 分治 高精度

原文链接https://www.cnblogs.com/zhouzhendong/p/9161557.html

题目传送门 - Codeforces 986D

题意

  给定一个数 $n(n\leq 10^{1500000})$ , 求满足 $(\prod b_i)\geq n$ 的 $\min(\sum b_i)$ 。

题解

  这题是下面链接中那题的加强版。

  BZOJ1263 [SCOI2006]整数划分 高精度

  这题的做法是预估出大概有多少个 $3$ ,然后最后几个数一个一个加上去就可以了。

  至于求 $3$ 的快速幂,要用FFT优化。

  时间复杂度:

$$T(m)=T(m/2)+m\log m=m\log m$$

  其中这里的 $m$ 与输入的 $n$ 的位数同阶。

  注意点:

  1.  本题卡常,要压位,我压了3位,但是2位好像也可以过。

  2.  注意一下 $n=1$ 的情况。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=(1<<21)+1;
const double PI=acos(-1.0);
int m;
char s[N];
int bit=1000;
struct Big{
	int len;
	LL a[N];
	void clear(){
		len=0;
		memset(a,0,sizeof a);
	}
	void print(){
		for (int i=len;i>=1;i--)
			printf("%03d",(int)a[i]);
		puts("");
	}
	bool operator >= (Big &x){
		if (len!=x.len)
			return len>x.len;
		for (int i=len;i>=1;i--)
			if (a[i]!=x.a[i])
				return a[i]>x.a[i];
		return 1;
	}
	void pushbits(){
		for (int i=1;i<=len;i++)
			a[i+1]+=a[i]/bit,a[i]%=bit;
		while (a[len+1]){
			len++;
			a[len+1]=a[len]/bit;
			a[len]%=bit;
		}
	}
	void operator *= (int x){
		for (int i=1;i<=len;i++)
			a[i]*=x;
		pushbits();
	}
}n,x,tmp;
struct C{
	double r,i;
	C(){}
	C(double _r,double _i){r=_r,i=_i;}
	C operator + (C x){return C(r+x.r,i+x.i);}
	C operator - (C x){return C(r-x.r,i-x.i);}
	C operator * (C x){return C(r*x.r-i*x.i,r*x.i+i*x.r);}
}A[N],B[N],w[N];
int R[N];
void FFT(C a[],int n){
	for (int i=0;i<n;i++)
		if (R[i]>i)
			swap(a[i],a[R[i]]);
	for (int t=n>>1,d=1;d<n;d<<=1,t>>=1)
		for (int i=0;i<n;i+=(d<<1))
			for (int j=0;j<d;j++){
				C tmp=w[t*j]*a[i+j+d];
				a[i+j+d]=a[i+j]-tmp;
				a[i+j]=a[i+j]+tmp;
			}
}
void Times (Big &a,Big &b,Big &c){
	int n,d;
	for (n=1,d=0;n<a.len+b.len;n<<=1,d++);
	for (int i=0;i<n;i++){
		R[i]=(R[i>>1]>>1)|((i&1)<<(d-1));
		w[i]=C(cos(PI*2*i/n),sin(PI*2*i/n));
		A[i]=B[i]=C(0,0);
	}
	for (int i=1;i<=a.len;i++)
		A[i-1].r=a.a[i];
	for (int i=1;i<=b.len;i++)
		B[i-1].r=b.a[i];
	FFT(A,n),FFT(B,n);
	for (int i=0;i<n;i++)
		A[i]=A[i]*B[i],w[i].i*=-1.0;
	FFT(A,n);
	c.clear();
	for (int i=0;i<n;i++)
		c.a[i+1]=(LL)(A[i].r/n+0.5);
	c.len=n;
	while (c.a[c.len]==0&&c.len>1)
		c.len--;
	c.pushbits();
}
void Pow(int y){
	if (y==0){
		x.clear();
		x.a[x.len=1]=1;
		return;
	}
	Pow(y/2);
	Times(x,x,x);
	if (y&1)
		x*=3;
}
bool check(Big &x,int y){
	tmp=x;
	tmp*=y;
	return tmp>=n;
}
int main(){
	scanf("%s",s+1);
	n.len=strlen(s+1);
	int pw10[3]={1,10,100};
	for (int i=1;i<=n.len;i++)
		n.a[(n.len-i+1-1)/3+1]+=pw10[(n.len-i)%3]*(s[i]-'0');
	m=max(0,(int)(n.len*log(10)/log(3))-3);
	n.len=(n.len-1)/3+1;
	if (n.len==1&&n.a[1]==1){
		puts("1");
		return 0;
	}
	Pow(m);
	while (1){
		for (int i=2;i<=4;i++)
			if (check(x,i)){
				printf("%d",m*3+i);
				return 0;
			}
		x*=3;
		m++;
	}
	return 0;
}

  

posted @ 2018-06-09 22:02  zzd233  阅读(709)  评论(0编辑  收藏  举报