Codeforces 986D Perfect Encoding FFT

题意:

给定一个数n,选出m个数使得 $\Pi_{i=1}^m a_i\ge n$,求$\sum_{i=1}^m a_i$的最小值 ,其中$m$的大小不限

$n$的长度$\le 10^6$

简单的计算可以发现 我们要尽量多的选$3$ 在最后特别逼近的时候 会有 $3^x\times2,3^x\times3,3^x\times4$三种选择

于是我们可以先求出一个逼近$n$的形如$3^x$的数$T$,之后暴力枚举三种情况,只要$T\ge n$则跳出 否则$T=T*3$继续枚举

对于一开始求出$T=3^x$的过程 我们可以发$x\le log_3 n=len(n)*log_310$ 求出$x$后可以通过 $FFT$+快速幂求出$T$

具体的复杂度不太会分析 我在实现时压了$2$位 看到别人有跑得飞快 开始怀疑是假做法了o(╥﹏╥)o

#include<bits/stdc++.h>
using namespace std;
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define pa pair<int,int>
#define mod 1000000007
#define ll long long
#define mk make_pair
#define pb push_back
#define fi first
#define se second
#define cl(x) memset(x,0,sizeof x)
#ifdef Devil_Gary
#define bug(x) cout<<(#x)<<" "<<(x)<<endl
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define bug(x)
#define debug(...)
#endif
const int INF = 0x7fffffff;
const int N=3e6+5;
/*
char *TT,*mo,but[(1<<15)+2];
#define getchar() ((TT==mo&&(mo=(TT=but)+fread(but,1,1<<15,stdin),TT==mo))?-1:*TT++)//*/
inline int read(){
    int x=0,rev=0,ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')rev=1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return rev?-x:x;
}
const int Mod=100;
int ans,K,ls;
int M,l,r[N];
char ss[N];

vector<int>s,g,f;
const double pi = acos(-1.0);
struct Cp{
    double x,y;
    Cp (double _x=0, double _y=0) {x=_x,y=_y;}
    Cp operator + (const Cp& rhs) {return Cp(x+rhs.x,y+rhs.y);}
    Cp operator - (const Cp& rhs) {return Cp(x-rhs.x,y-rhs.y);}
    Cp operator * (const Cp& rhs) {return Cp(x*rhs.x-y*rhs.y,x*rhs.y+y*rhs.x);}
}A[N],B[N],x,w,w0;
inline void FFT(Cp *A,int f) {
    int i,j,k;
    for(i=0;i<M;i++) if(i<r[i]) swap(A[i],A[r[i]]);
    for(i=1;i<M;i<<=1) {
        w.x=cos(pi/i),w.y=sin(pi/i)*f;
        for(j=0;j<M;j+=i<<1) {
            w0.x=1,w0.y=0;
            for(k=0;k<i;++k) {
                x=A[j+k];
                A[j+k]=x+(w0*A[i+j+k]);
                A[i+j+k]=x-(w0*A[i+j+k]);
                w0=w0*w;
            }
        }
    }
    if(f==-1) for(i=0;i<M;++i) A[i].x/=M;
}

void stretch(vector<int>&a){
    int p=0,la=a.size();
    for (int i=0;i<la||p;++i) {
        if(i>=la) a.pb(0);
        ll cur=a[i]+p;
        a[i]=cur%Mod;
        p=cur/Mod;
    }
}
bool cmp(vector<int>a){
    int la=a.size(),lb=s.size();
    if(la<lb) return 0;
    if(la>lb) return 1;
    for(int i=la-1;~i;i--) {
        if(a[i]<s[i]) return 0;
        if(a[i]>s[i]) return 1;
    } 
    return 1;
}
bool work(int x){
    vector<int>h;
    for(int i=0;i<g.size();i++) h.pb(g[i]*x);
    stretch(h);
//  for(int i=0;i<h.size();i++) cout<<h[i]<<" ";cout<<endl; 
    return cmp(h);
}
void solve2(){
    for(int i=0;i<g.size();i++) g[i]=g[i]*3;
    stretch(g); 
}
//calc 3^n
vector<int> solve(vector<int>a,vector<int>b){
    int la=a.size(),lb=b.size();
//  for(int i=0;i<a.size();i++) cout<<a[i]<<" ";cout<<endl; 
//  for(int i=0;i<b.size();i++) cout<<b[i]<<" ";cout<<endl; 
//  bug(la),bug(lb);
    for(M=1,l=0;M<=la+lb;M<<=1,l++);
    for(int i=0;i<a.size();i++) A[i].x=a[i],A[i].y=0; 
    for(int i=0;i<b.size();i++) B[i].x=b[i],B[i].y=0; 
    for(int i=1;i<M;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    FFT(A,1),FFT(B,1);
    for(int i=0;i<M;i++) A[i]=A[i]*B[i];
    FFT(A,-1);
    vector<int>z(la+lb-1);
    for(int i=0;i<=la+lb-2;i++) z[i]=(int)(A[i].x+0.5);
    for(int i=0;i<M;i++) A[i].x=B[i].x=A[i].y=B[i].y=0;
//  for(int i=0;i<z.size();i++) cout<<z[i]<<" ";cout<<endl; 
    return z;
}
void calc(){
    f.pb(3),g.pb(1);
    while(K){
        if(K&1) g=solve(g,f),stretch(g);
        K>>=1,f=solve(f,f),stretch(f);
    }
}
int tt[10]={0,1,2,3,4,5,5,6,6,6};
int main(){
#ifdef Devil_Gary
    freopen("in.txt","r",stdin);
#endif
    scanf("%s",ss),ls=strlen(ss),reverse(ss,ss+ls);
    if(ls==1){
        int zjq=ss[0]-'0'; return cout<<tt[zjq]<<endl,0;
    }
    for(int i=0;i<ls;i+=2) {
        int x=ss[i]-'0';
        if(i+1<ls) x+=(ss[i+1]-'0')*10;
//      if(i+2<ls) x+=(ss[i+2]-'0')*100;
        s.pb(x);
    }
    K=(ls-1)*(double)(log(10)/log(3)),--K,ans+=K*3,calc();
    int ans2=ans;
//  for(int i=0;i<s.size();i++) cout<<s[i]<<" ";cout<<endl; 
    for(;;ans+=3,solve2()){
//      for(int i=0;i<g.size();i++) cout<<g[i]<<" ";bug(ans),cout<<endl; 
        if(work(2)) {ans+=2;break;}
        else if(work(3)) {ans+=3;break;}
        else if(work(4)) {ans+=4;break;}
    }
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/devil-gary/p/9115297.html