codefroces 991F 性质分析

题目分析

由于 n 10 10 ,所以除了 10 10 外,其他数都是9位,所以如果我们要更换表示法,这个新表示法应该要小于等于8位。而 10 10 的最简表示法显然也不会超过8位。

考虑表示法里会有几个加号。发现把一个简单数字(即不带乘号和幂号的项)表示为一个简单数字加一个简单数字的形式,位数一定不会减少,因此加号串联的几个项中,最多有一个项是简单数字,又因为表示法不能超过8位,所以最多用2个加号,并且这三项的长度分别是3,3,1。又因为9^9+9^9+9=774840987并没有减少表示法长度,所以加号最多有一个。

接着发现,一个 x 位的简单数字 A 和一个 y 位的简单数字 B 相乘,结果的位数不会大于 x + y 。所以一个项也不能写成 A B 的形式,因而如果要将 n 更换表示法,其中一定有一个幂次表达(即表示法中一定存在a^b的形式。)

那么我们可以把所有能够被幂次表达,且小于 n 的数及它的最简幂次表达用一个map存一下,这个总共是根号级别的。然后取每一个幂次表达,将其写成C*a^b+D的形式,其中C和D是简单数字或被幂次表达的项,并且 C = n a b D = n mod a b

这个做法看起来很正确,但是这时候有Lcy发问了,凭什么 C D 就是这样取的呢?能不能把 C 稍微减小一点,使得 C 位数减小,并且 D 位数不变,使得表示法更优呢?

既然 C 位数可以减小,说明至少有两位。a和b至少一位,D至少一位,加上三个符号,正好是8位。由于C减小1后,D要变成 ( D + a b ) ,应该还是1位,所以 a b 一定是一个一位数。我们发现会发生Lcy提问条件的数 n ,都是两位数,根本不需要写成C*a^b+D的形式,所以我们不用考虑这个问题,该做法正确。

代码

注意要用C++17提交,C++11太慢了QAQ

#pragma G++ optimize (2)
#include<bits/stdc++.h>
using namespace std;
#define RI register int
typedef long long LL;
LL n,sqn;string ans;
map<LL,string> mp;
int main()
{
    cin>>n;
    sqn=sqrt(n);
    for(LL i=2;i<=sqn;++i) {
        string ii=to_string(i);
        if(!mp.count(i)||mp[i].length()>ii.length()) mp[i]=ii;
        for(LL j=i*i,k=2;j<=n;j*=i,++k) {
            string kl=ii+"^"+to_string(k);
            if(!mp.count(j)||mp[j].length()>kl.length()) mp[j]=kl;
        }
    }
    ans=to_string(n);
    for(map<LL,string>::iterator it=mp.begin();it!=mp.end();++it) {
        string kl;LL x=(*it).first;
        if(n/x!=1) {
            string y=to_string(n/x);
            if(mp.count(n/x)&&mp[n/x].length()<y.length()) kl+=mp[n/x]+"*";
            else kl+=y+"*";
        }
        kl+=(*it).second;
        if(n%x!=0) {
            string y=to_string(n%x);
            if(mp.count(n%x)&&mp[n%x].length()<y.length()) kl+="+"+mp[n%x];
            else kl+="+"+y;
        }
        if(kl.length()<ans.length()) ans=kl;
    }
    cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/litble/article/details/80996298