PAT乙级 1049 数列的片段和 (20分) PAT甲级 1104 Sum of Number Segments (20分)

1049 数列的片段和 (20分)

给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) (0.4) 这 10 个片段。

给定正整数数列,求出全部片段包含的所有的数之和。如本例中 10 个片段总和是 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0。

Given a sequence of positive numbers, a segment is defined to be a consecutive subsequence. For example, given the sequence { 0.1, 0.2, 0.3, 0.4 }, we have 10 segments: (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) and (0.4).

Now given a sequence, you are supposed to find the sum of all the numbers in all the segments. For the previous example, the sum of all the 10 segments is 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0.

输入格式:

输入第一行给出一个不超过 10​5​​ 的正整数 N,表示数列中数的个数,第二行给出 N 个不超过 1.0 的正数,是数列中的数,其间以空格分隔。

Each input file contains one test case. For each case, the first line gives a positive integer N, the size of the sequence which is no more than 10​5​​ . The next line contains N positive numbers in the sequence, each no more than 1.0, separated by a space.

输出格式:

在一行中输出该序列所有片段包含的数之和,精确到小数点后 2 位。

For each test case, print in one line the sum of all the numbers in all the segments, accurate up to 2 decimal places.

输入样例:

4
0.1 0.2 0.3 0.4

输出样例:

5.00

感谢 Ruihan Zheng 对测试数据的修正。

思路:

大人,时代变了!!!
这个题似乎在2020年6月17左右更改了数据和答案,所以说,包括书上的答案,很多大佬写的博客,还有我以前的代码都过不了了。主要的更改的地方是第三个测试点,我猜测主要是浮点数精度的修正。
这个题的作者是CAO, Peng,他的题很多都是需要动点小脑筋的,而不主要是书本上的知识。
通读这个题的题目,感觉蛮复杂的,但是仔细想一下,我们没有必要把每个数列片段全穷举出来。换个思路想想,把所有数列片段混合起来看,每个数共出现过多少次。
在这里插入图片描述
但是怎么处理精度问题呢?第一种方法可以参考高精度运算的思路,当然高精度的代码比较多。
第二种方法就是,把小数点后面的部分抬到整数部分,比如0.1,乘10以后就变成1了,当做整型来处理,不会有精度损失,后序处理的时候再除回去就行了。但是这种方法需要注意最后的结果会不会溢出,如果一个数小数点后有3位,那么我至少需要乘1000才行,总的数据规模是105,出现次数最多的数(也就是中间那个),接近出现1010次,按最坏情况下每个数都是1,那结果最坏打算是1015左右,所以int类型肯定是不够的(int 只能处理10的9次方)。long long 类型大约能承载1019大小的数,所以小数点后如果只有3 4位的还是可以接受的,再大long long 也不行了,只能用高精度。
题目并没有给出小数点后最多是多少位,但是PAT的独特的成绩判定(你能知道每个测试点是过还是没过,而且出错的话你能知道错误类型),所以你可以写一些数据探针代码(自己编的名词)来测试一下。
在这里插入图片描述

在这里插入图片描述
通过这两次提交你至少能知道,小数点后最多就是三位,而且正是测试点3.当然我还提交过多次,这里就不放图了。测试点一二都是只有小数点后一位。测试点四存在整数,也就是1或者0(没有小数点).

统计数据:

在这里插入图片描述

题解 方法一:

#include <cstdio>
using namespace std;
#define ll long long

ll n,summ,tmpa;
double tpda;

int main(){
    scanf("%lld",&n);
    for(ll i=0;i<n;++i){
        scanf("%lf",&tpda);
        tmpa = ((ll)(tpda*10000)+5)/10;  //从结果上来看,这么做吧原来的浮点数乘以1000再转为整型
        summ += tmpa * (i+1) * (n-i);  //为什么要先乘以一万再加5除以十?是因为最低位会产生精度误差。
    }                                  //加五除十是为了四舍五入
    printf("%lld.%02lld",summ/1000,((summ%1000)+5)/10);
    return 0;
}

题解 方法二:

这是改了数据后第一次AC的代码,思路还有点不太清晰,仅供参考。

#include <bits/stdc++.h>
using namespace std;
#define ll long long

ll n,summ,tmp,tmpa;
char cnum[1000];

ll poww(ll a,ll b){
    ll c=a;
    while(--b)
        c *= a;
    return c;
}

int main(){
    printf("%lld",poww(10,5));
    scanf("%lld",&n);
    for(ll i=0;i<n;++i){
        scanf("%s",cnum);
        if(cnum[0]=='1')
            summ += 1 * poww(10,4) * (i+1) * (n-i);
        else{
            sscanf(cnum,"0.%lld",&tmp);
            summ += tmp * poww(10,6-strlen(cnum)) * (i+1) * (n-i);
        }
    }
    printf("%lld.%02lld",summ/poww(10,4),(summ%poww(10,4)+5*poww(10,1))/poww(10,2));
    return 0;
}

题解 方法三:

这是以前能AC的代码,现在不行了。

#include <cstdio>
using namespace std;

int n;
double nums[110000],summ=0;

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%lf",&nums[i]);
        summ += nums[i] * (i+1)*(n-i);
    }
    printf("%.2f",summ);
    return 0;
}
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值