2023-2024 ICPC Higher Arithmetic

2023-2024 Higher Arithmetic

题目

Captchas are getting more and more elaborate. It started with doing simple calculations like 7 + 2 7 + 2 7+2, and now, it has evolved into having to distinguish chihuahuas from double chocolate chip muffins.

To combat the rise of smarter bots, the Internet Captcha Production Company (ICPC) has outdone itself this time: given a distorted image containing many integers, find the maximum value that can be expressed using each of the given integers exactly once, using addition, multiplication, and arbitrary parentheses.

After unsuccessfully trying to solve such a captcha for an hour straight, Katrijn is terribly frustrated. She decides to write a program that outputs a valid arithmetic expression with maximal value.

Input

The input consists of:

  • One line with an integer n n n ( 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105), the number of integers in the captcha.
  • One line with n n n integers a a a ( 1 ≤ a ≤ 1 0 6 1 \le a \le 10^6 1a106), the integers in the captcha.

Output

Output a valid arithmetic expression with maximal value, where each integer from the input list is used exactly once. The usual order of operations applies. The output expression may use at most 1 0 6 10^6 106 characters and must not contain any spaces. Such an expression exists for any possible input.

If there are multiple valid solutions, you may output any one of them.
Examples
case1:
input

4
1 2 3 4

output

3*((1+2)*4)

case2:
input

3
13 37 1

output

(1+13)*37

**
case3:
input

4
1 1 1 1

output

((1+1)*(1+1))

题目翻译

给你 一个数字 n , 再给你 n 个数字,让你用括号、+ 和 × 搭配,使得你所组成的式子按照你的运算后 值最大

  • 很明显,+ 不如 ×,只有个别的数字要处理,其他都用 ×
  • 题目对答案的正确判断一定是根据你的式子运算后的数值判断正确,所以对于括号要求不严格
  • 对于1 和 2 来说,合并成为多少,使得乘法合最大呢?

令 k 个 1 合成 k,(k + 1)个 1 合成 (k + 1),一共有n个1,那么运算的式子就是
k n k < ( k + 1 ) n ( k + 1 ) k^{\frac{n}k}<(k+1)^{\frac{n}{(k+1)}} kkn<(k+1)(k+1)n 两边同时取 l n ln ln
n k l n k < n ( k + 1 ) l n ( k + 1 ) \frac{n}kln{k}<\frac{n}{(k+1)}ln{(k+1)} knlnk<(k+1)nln(k+1)两边消掉 n n n
l n k k < l n ( k + 1 ) ( k + 1 ) \frac{ln{k}}k<\frac{ln{(k+1)}}{(k+1)} klnk<(k+1)ln(k+1)
这不就是 l n x x \frac{ln{x}}x xlnx吗,在 x = e x = e x=e的时候取最大值,但是我们是整数,所以3比2大,也就是说,能凑成3就凑成 3

  • 因为能凑成3就凑成3,所以2也能凑成3
  • 所以 1 和 2 一起凑成3
  • 1 剩下1个或两个怎么办呢?

  • 如果剩下1个 只能把1加入前面或者后面,后面的数字一定是 > = 3 >=3 >=3,如果是3,加入前面后面都一样,如果后面不是3,加入前面更好,这样两边更趋近一些,乘积更大。
  • 所以剩下1个直接给前面
  • 如果剩下两个呢?很明显2个1组成“ ( 1 + 1 ) (1+1) (1+1)”变成2乘进去更好

再最后把其他的数字乘进去就完了

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
#define endl '\n'

int dp[3];//记录1,2的个数
int n,;

void solve()
{
    cin >> n;
    priority_queue<int, vector<int>, greater<int>> q;

    for (int i = 1; i <= n; i++)
    {
        int x; cin >> x;
        if (x == 1 || x == 2)
            dp[x]++;
        else
            q.push(x);
    }
    
    string ans;
    
    if(dp[1] <= dp[2])
    {
        for (int i = 1; i <= dp[1]; i ++)
            ans += "(1+2)*";
            
        dp[2] -= dp[1], dp[1] = 0;
        
        while(dp[2]--)  ans += "2*";
    }else if(dp[1])
    {
        bool ok = 0;
        for (int i = 1; i <= dp[2];i++)
        {
            ans += "(1+2)*";
            ok = 1;
        }
        dp[1] -= dp[2], dp[2] = 0;
        int cnt = dp[1] / 3;
        int yv = dp[1] % 3;
        while(cnt--)
        {
            ans += "(1+1+1)*";
            ok = 1;
        }
        if(yv == 1)
        {
            if(ok)
            {
                ans[ans.size() - 2] = '+';
                ans[ans.size() - 1] = '1';
                ans += ")*";
            }else if(q.size() > 0)
            {
                int x = q.top();
                q.pop();
                string s;
                while(x)
                {
                    s = char(x % 10 + '0') + s;
                    x /= 10;
                }
                ans = ans + "(1+" + s + ")*";

            }else
                ans += "1*";
        }else if(yv == 2)
            ans += "(1+1)*";
    }
    if(ans.size())
    {
        for (int i = 0; i < ans.size() - 1; i ++)
            cout << ans[i];
    }

    bool ok = 0;
    while(q.size())
    {
        if(ans.size() || ok)
            cout << "*";
        ok = 1;
        cout << q.top();
        q.pop();
    }
}
signed main()
{
    solve();
    return 0;
}
  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值