关于数字的爆炸

  好像已经不是第一次发生同样的事了,我一本正经理直气壮地说题目并没有打错,然后我那个神犇学(er)长(zi)就往代码上一指,说你这个地方不就爆了吗,特别尴尬。

  大概总结一下,关于计算过程中数字上会出现的问题,撇去算错==,大致就是溢出精度的问题。

  精度的问题有一种很明显,就是最终存储某个值的变量,比如说答案最后是超过int/longint范围的,那么存答案的变量就要想到开long long/int64之类的,以自身经历来看,这个问题不是很容易出错,主要爆精度的问题容易出在运算过程中,可能计算的时候长长的一个式子,在计算到某个部分的时候,有个临时存储的变量,就是在这个地方爆掉了,比如说1<<k表示2^k,运算过程中1是临时存储的变量,1是int/longint的,当1<<k超过int/longint时就爆了,那么应该写成(long long)1或1LL或int64(1)用强制转换,或者加一个中间变量之类的,按照四则运算法则运算,对于中间的每一步运算,该步的答案是存在前一个里的(#很显然),比如a+b,这一步答案存在a里,还有一个就是精度的问题,其中一方面是向上/下取整,这个一般没什么问题,还有一个就是涉及到除法(#显然是非整除)时要比较大小或者计算某个会有问题,主要避免就是比较时尽可能乘,不要除,计算的时候尽可能把除集中起来放后面一起做。#这里有些不同写法是Pascal和C++的不同表示,意义还是一样的

  今天的题,很不幸,精度和溢出都被我碰上了==再见再见再见

  题目是给n个数,需要求一个区间[i,j],满足该区间方差最大,同时i尽可能小,然后都满足的话j也尽可能小

  方差公式是 S=[(X1-X)^2+(X2-X)^2+……+(Xn-X)^2]/n,其中X是平均数  数据范围是n≤2000,Xi≤1000

  显然是n^2暴力就可以过的,把方差式子整理一下可得

  S=[Σ(Xi^2)-2·X·ΣXi+n·X^2]/n

    =[Σ(Xi^2)-2·(ΣXi/n)·ΣXi+n·(ΣXi/n)^2]/n

    =[Σ(Xi^2)-2·(ΣXi)^2/n+(ΣXi)^2/n]/n

    =[Σ(Xi^2)-(ΣXi)^2/n]/n

  Xi^2和Xi的和都可以前缀和提前处理出来,所以当时我用g[i]表示Xi^2的前缀和,f[i]表示X的前缀和,

条件是g[j]-g[i-1]-sqr(f[j]-f[i-1])/(j-i+1)>ans·(j-i+1),然后就是精度问题炸成40,于是把式子中除消掉变成了

(g[j]-g[i-1])·(j-i+1)-sqr(f[j]-f[i-1])>ans·sqr(j-i+1),然后因为ans用分数表述ans=ansx/ansy,式子又变成

(g[j]-g[i-1])·(j-i+1)-sqr(f[j]-f[i-1])>ansx/ansy·sqr(j-i+1) → ansy·((g[j]-g[i-1])·(j-i+1)-sqr(f[j]-f[i-1]))>ansx·sqr(j-i+1)

其中ansx初值0,ansy初值1,然后发现只有80分

当时主要是因为按照方差原来的式子,运算过程中是不会溢出的,然后为了消去除法,两边同时乘上一些数,导致溢出爆掉了,把g改成int64就可以了,反正只要让算术过程中的存储的不爆掉就好了。

  类似问题其实很多,算的时候一定要注意,否则可能到最后就是怀揣着一颗想要AK的心,结果爆零了#huaji

【写的有漏洞的,欢迎路过大神吐槽】

 2016/11/9 23:35:01

 Ending. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值