Notice:
1.一开始直接写嵌套循环,发现超时。所以需要用数学方法去求解。
后参考别人博客,发现其规律:
先观察一个数,例如,对于N=4的数列中序列号为3的数所在的片段如下:
(起点为1)[(1,2,3),(1,2,3,4)];
(起点为2)[(2,3),(2,3,4)];
(起点为3)[(3),(3,4)];
可以看出来,包含第i个数的片段中,片段的起始可以是1,2,3..i,一共i种选择,
(如包含3的片段有123三种选择) 片段的结尾可以是i,i+1,...n,一共n-i+1种选择。
(如包含3的片段有34两种选择)。
由此推广,对于长度为N的数列中序列号为i的数,所在的片段可分为i个部分,第i部分起点为i,
终点分别为i,i+1,i+2,...,N,共(N-i+1)个,故序列i的出现次数为i*(N-i+1)。
http:
2.关于long long sum:
“N比较大时,double类型的值多次累加导致的精度误差,因为输入为十进制小数,存储到double中时,
计算机内部使用二进制表示,且计算机的字长有限,有的十进制浮点数使用二进制无法精确表示
只能无限接近,在字长的限制下不可避免会产生舍入误差,这些细微的误差在N较大时多次累加
会产生较大误差,所以建议不要使用double类型进行多次累加的精确计算,而是转为能够精确存储
的整型。尝试把输入的double类型的值扩大1000倍后转为long long整型累加,同时使用
long long类型保存sum的值,输出时除以1000.0转为浮点型再输出(相当于把小数点向后移动3位后
再计算,避免double类型的小数部分存储不精确,多次累加后对结果产生影响) 但我觉得乘以1000
也未必严谨,可能测试样例最小只有小数点后三位,如果测试样例变成小数点后四位、五位、六位,
乘以1000相当于直接在小数点后三位处截断,而原本第四五六位经过多次累加进位后依然可能会引起
精度问题,但如果乘以10000就会超出long long的值,我认为最精确的应该是截取到所有小数中最大
的位数的那一位。。可能我的想法有疏漏,经过测试,测试样例确实没有超过小数点后三位,
虽然修改为乘以1000后代码已经AC,但如果对测试样例稍加修改,可能又会导致不AC了…
所以这道题先打个问号吧,我猜可能将来题目样例还会被修改…”
我的 (该代码超时)
#include <iostream>
#include <cstdio>
using namespace std;
int main(){
int n;
cin >> n;
float a[n];
for(int i = 0;i < n;i++){
cin >> a[i];
}
float sum1 = 0,sum2 = 0;
for(int i = 0;i < n;i++){
sum1 = 0;
for(int j = i;j < n;j++){
sum1 += a[j];
sum2 += sum1;
}
}
printf("%.2f",sum2);
return 0;
}
柳诺的代码
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
double temp;
long long sum = 0;
for(int i = 1;i <= n;i++){
cin >> temp;
sum += (long long)(temp * 1000) * i * (n - i + 1);
}
printf("%.2f",sum / 1000.0);
return 0;
}
|