给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 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.
输入第一行给出一个不超过 105 的正整数 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 105 . 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
大人,时代变了!!!
这个题似乎在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
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
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
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;
}