Codeforces 991

991 F

题意

给一个 \(\le 10^{10}\) 的正整数,使用'0'~'9','+','*','^'//乘方字符表示这个数。求表示方法所形成的字符串长度最小的一种。

Examples

Input
2018
Output
2018
Input
1000000007
Output
10^9+7
Input
10000000000
Output
100^5
Input
2000000000
Output
2*10^9

首先,仅用'+','*'不能减小长度。
其次,乘方的底数必然 \(\le \sqrt{n}\)
再次,所有的数最多只能表示为 \(a^b*c^d+e^f\) 的形式。
于是,brute force枚举所有情况即可。中间可以用一些小小的优化,如二分。
复杂度\(O(玄学)≈O(\sqrt{n}\log n)\)

Code

#include<bits/stdc++.h>
#define INF 1050000000
using namespace std;
typedef long long D;
D n;
D len(D a){
    if(!a)return 1;
    D ret=0;
    while(a)ret++,a/=10;
    return ret;
} 
struct data{
    D a,b,c,d,e,f,val,l; //a^b*c^f+d^e
    data():c(1),d(0),e(1),f(1){}
    data(D _a,D _b,D _val):a(_a),b(_b),c(1),d(0),e(1),f(1),val(_val){}
    bool operator <(const data& dat)const{
        return val==dat.val?l<dat.l:val<dat.val;
    }
    void calc(){
        l=len(a)+len(b)+len(c)+len(d)+len(e)+len(f)+5;
        if(b==1)l-=2;
        if(c==1)l-=2;
        if(d==0)l-=2;
        if(e==1)l-=2;
        if(f==1)l-=2;
    }
}a[1000000],b[1000000];
D cnt;
int main(){
    cin>>n;
    a[++cnt]=data(n,1,n);
    a[cnt].calc();
    b[cnt]=a[cnt];
    for(D i=2;i*i<=n;i++){
        for(D j=i,k=1;j<=n;j*=i,k++){
            a[++cnt]=data(i,k,j);
            a[cnt].c=n/a[cnt].val;
            a[cnt].d=n-a[cnt].val*a[cnt].c;
            a[cnt].calc();
            b[cnt]=a[cnt];
        }
    }
    sort(b+1,b+cnt+1);
    for(D i=1;i<=min(cnt,10000ll);i++){
        for(D j=1;j<=100;j++){
            D l=1,r=cnt,mid,ans=-1;
            while(l<=r){
                mid=(l+r)>>1;
                if(a[i].val*j+b[mid].val==n)ans=mid,r=mid-1;
                else if(a[i].val*j+b[mid].val<n)l=mid+1;
                else r=mid-1;
            }
            if(ans!=-1){
                a[++cnt]=a[i];
                a[cnt].c=j;
                a[cnt].d=b[ans].a;
                a[cnt].e=b[ans].b;
                a[cnt].calc();
            }
        }
    }
    for(D i=1;i<=min(cnt,500000ll);i++){
        D l=1,r=cnt,mid,ans=-1;
        while(l<=r){
            mid=(l+r)>>1;
            if(a[i].val*b[mid].val<=n)ans=mid,l=mid+1;
            else r=mid-1;
        }
        if(ans!=-1){
            a[++cnt].a=a[i].a;
            a[cnt].b=a[i].b;
            a[cnt].c=b[ans].a;
            a[cnt].f=b[ans].b;
            a[cnt].d=n-a[i].val*b[ans].val;
            a[cnt].calc();
        }
    }
    int minn=INF,mini;
    for(D i=1;i<=cnt;i++){
        if(a[i].l<minn){
            minn=a[i].l;
            mini=i;
        }
    }
    cout<<a[mini].a;
    if(a[mini].b!=1)cout<<"^"<<a[mini].b;
    if(a[mini].c!=1)cout<<"*"<<a[mini].c;
    if(a[mini].f!=1)cout<<"^"<<a[mini].f;
    if(a[mini].d!=0)cout<<"+"<<a[mini].d;
    if(a[mini].e!=1)cout<<"^"<<a[mini].e;
    return 0;
}

转载于:https://www.cnblogs.com/BlogOfchc1234567890/p/10322993.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值