日常训练 20170612 钥匙

题意简述:
  给定一个由 N 个实数组成的序列 a1,a2,,an,你需要求出对于所有的满足 1ijn 整数 i,j ri=lai 的最大值是多少。
输入格式:
  第一行是一个整数 n
  第二行有 n 个由空格分隔的实数 a1,a2,a3,,an1,an
输出格式:
  如果答案 k=0 或者 1|k|<10 ,那么请直接输出答案并保留三位小数。否则,若答案用科学计数法表示为 a×10b (其中 1|a|10 b 是整数),你需要输出 aEb,其中 a 要保留三位小数。
题解:
  一开始想只要取个对数就能随便做了,但写着写着就感觉细节很麻烦,乘积有正有负,所以要正负分开考虑,如果答案也分正负更新会写得很麻烦,不难发现元素不少于 2 个时答案非负(可以用前缀积和鸽巢原理简单证明)。那么我们做了前缀积之后只要用前后两个前缀积同正或同负来更新了。还有一些初值细节,比如对于前后同正的前缀积计算时前缀积最小值可以设初值为 1 ,表示可以是原序列从第 1 个元素开始的前缀,但是对于前后都负的前缀积计算时前缀积最小值是不能简单设初值处理,只能记录前缀积最小值存不存在,而很难设初值处理。

#include<bits/stdc++.h>
typedef long double ld;
const int N = 1e5 + 10;
const long double eps = 1e-7;
int n, mxf, sumf;
long double mx, mn, sum, temp, a[N];
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%Lf", &a[i]);
    if (n == 1) {
        if (fabs(a[1]) < 10 && fabs(a[1]) >= 1) {printf("%.3Lf\n", a[1]); return 0; }
        if (a[1] < -eps) printf("-"), a[1] = -a[1];
        a[1] = log(a[1]) / log(10);
        printf("%.3fE%d\n", pow(10, a[1] - floor(a[1])), (int)floor(a[1]));
        return 0;
    }

    mx = -100;

    sumf = 1;
    sum = 0;
    mn = 0;
    bool updated = 0;
    for (int i = 1; i <= n; i++) {
        if (fabs(a[i]) < eps) {sumf = 1; sum = 0; mn = 0; updated = 0; continue;}
        sum += log(fabs(a[i])) / log(10);
        if (a[i] < -eps) sumf *= -1;
        if (sumf == -1) {
            if (updated)
                mx = std::max(mx, sum - mn),
                mn = std::min(mn, sum);
            else
                mn = sum,
                updated = 1;
        }
    }

    sumf = 1;
    sum = 0;
    mn = 0;
    for (int i = 1; i <= n; i++) {
        if (fabs(a[i]) < eps) {sumf = 1; sum = 0; mn = 0;continue;}
        sum += log(fabs(a[i])) / log(10);
        if (a[i] < -eps) sumf *= -1;
        if (sumf == 1)
            mx = std::max(mx, sum - mn),
            mn = std::min(mn, sum);
    }

    if (mx < 1)
        printf("%.3f\n", pow(10, mx));
    else
        printf("%.3fE%d\n", pow(10, mx - floor(mx)), (int)floor(mx));
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值