P4157 [SCOI2006]整数划分
分析:
要使乘积最大,考虑到要使指数大一些, 4 = 2 2 4=2^2 4=22 ,因此两个 2 2 2 可由一个 4 4 4 替换, 3 2 > 2 3 3^2 > 2^3 32>23 ,所以要使 3 3 3 尽量多。
对于最后一个数取什么要做分类讨论:
- n % 3 = 0 n\% 3=0 n%3=0 ,取 3 3 3
- n % 3 = = 1 n\%3==1 n%3==1 ,去掉一个 3 3 3换成 4 4 4
- n % 3 = = 2 n \%3==2 n%3==2 , 取 2 2 2
然后就是处理高精度乘法了,这里用的是 F F T FFT FFT , n < = 31000 n<=31000 n<=31000 , n / 3 < 10400 n/3<10400 n/3<10400 ,因为并不知道是哪两个确切的数相乘,这里采取的方法是将 3 32 ( 2 5 ) 3^{32(2^5)} 332(25) , 3 64 ( 2 6 ) 3^{64(2^6)} 364(26) , 3 128 ( 2 7 ) 3^{128(2^7)} 3128(27) … 3 8192 ( 2 12 ) 3^{8192(2^{12})} 38192(212) 通过打表的方式得出来,然后再依次比较 n / 3 n/3 n/3 与 8192 8192 8192 到 32 32 32 的大小,若大于等于,则结果乘上 3 b a s e 3^{base} 3base ,最后还有多余,直接在结果里做乘法即可。
弱弱的吐槽一下: p r e ( ) pre() pre() ,没有对 A A A 和 B B B 清空,根本就没想到清空, d e b u g debug debug d e de de 了 一个多小时,不讲恶徳~~~
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
const int N = (1<<21)+5;
const double PI=acos(-1);
struct Complex
{
double x, y;
Complex operator+(const Complex &o) const{return{x+o.x,y+o.y};}
Complex operator-(const Complex &o) const{return{x-o.x,y-o.y};}
Complex operator*(const Complex &o) const{return{x*o.x-y*o.y,x*o.y+y*o.x};}
}A[N],B[N],C[12][N],t[N];
int rev[N];
void init(int k)
{
int s=1<<k;
for(int i=1;i<s;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
}
void fft(Complex *a,int n,int inv)
{
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int len=1;len<n;len<<=1)
{
Complex Wn=Complex({cos(PI/len),inv*sin(PI/len)});
for(int i=0;i<n;i+=len*2)
{
Complex w=Complex({1,0});
for(int j=0;j<len;j++,w=w*Wn)
{
Complex x=a[i+j],y=w*a[i+j+len];
a[i+j]=x+y,a[i+j+len]=x-y;
}
}
}
if(inv==-1) for(int i=0;i<n;i++) A[i].x = A[i].x/n+0.5; // 精度
}
// --------FFT
int ans[N], deep[15]; // deep 用来存位数
void pre(Complex *a, Complex *b,Complex *c, int &n, int m)
{
// A, B 一定要清空,因为用到的不仅仅是 [0,n-1],而是 [0,s-1]
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
for(int i=0;i<n;i++) A[i] = a[i];
for(int i=0;i<m;i++) B[i] = b[i];
int k=1, s=2;
while(s < n+m-1) k++, s<<=1;
init(k);
fft(A,s,1); fft(B,s,1);
for(int i=0;i<s;i++) A[i] = A[i]*B[i];
fft(A,s,-1);
memset(ans,0,sizeof(ans));
for(int i=0;i<s;i++)
{
ans[i] += (int)(A[i].x);
ans[i+1] += ans[i]/10;
ans[i] %= 10;
}
while(!ans[s] &&s >-1) s--;
for(int i=0;i<=s;i++) c[i].x = (double)ans[i];
n=s+1;
/*cout<<n<<endl;
for(int i=s;i>=0;i--) cout<<ans[i];
cout<<endl;*/
}
void build()
{ // 打表
ll base = pow(3,32);
int tot=0;
while(base)
{
C[0][tot++].x = base%10;
base /= 10;
}
//cout<<tot<<endl;
deep[0] = tot;
for(int i=1;i<=9;i++)
{
pre(C[i-1],C[i-1],C[i],tot,tot);
deep[i] = tot;
//cout<<tot<<endl;
}
}
signed main()
{
build();
int n;
cin>>n;
int yu=1;
if(n%3==1) yu=4, n-=4;
if(n%3==2) yu=2, n-=2;
int cnt=n/3;
if(cnt<32)
{
int res = yu*pow(3,cnt);
int tmp=res, len=0;
while(tmp) len++, tmp /= 10;
cout<<len<<endl<<res;
return 0;
}
int p=8, base = (1<<13);
// 找到第一个满足条件的
while(cnt < base) base >>= 1, p--;
cnt -= base;
// Coplex t[] 用来暂存结果
for(int i=0;i<deep[p];i++) t[i] = C[p][i];
int cn=deep[p];
while(p >= 0)
{
if(cnt >= base)
{
pre(t, C[p], t, cn , deep[p]);
cnt -= base;
}
base >>= 1;
p--;
}
if(cnt) yu *= pow(3,cnt);
memset(ans,0,sizeof(ans));
for(int i=0;i<cn;i++)
{
ans[i] += (int)(t[i].x)*yu;
ans[i+1] += ans[i]/10;
ans[i] %= 10;
}
while(ans[cn])
{
ans[cn+1] += ans[cn]/10;
ans[cn] %= 10;
cn++;
}
while(!ans[cn] && cn > -1) cn--;
cout<<cn+1<<endl;
for(int i=cn;i>=max((ll)0,cn-99);i--) cout<<ans[i];
return 0;
}