Google Code Jam 2008第1A轮问题3

时间:2013-09-23 16:21:50

标签: algorithm integer-overflow

对于Google Codejam 2008中的problem statement:第1A轮问题3

  

在这个问题中,您必须找到之前的最后三位数字   数字的小数点(3 +√5) n

     

例如,当n = 5时,(3 +√5) 5 = 3935.73982 ......   答案是935。

     

对于n = 2,(3 +√5) 2 = 27.4164079 ......答案是027。

我的解决方案基于T(i)= 6 * T(i-1) - 4 * T(n-2)+ 1的思想,其中T(i)是n = i的整数部分是下面:

#include<stdio.h>
int a[5000];
main(){
    unsigned long l,n;
    int i,t;
    a[0]=1;
    a[1]=5;
    freopen("C-small-practice.in","r",stdin);
    scanf("%d",&t);
    for(i=2;i<5000;i++)
            a[i]=(6*a[i-1]-4*a[i-2]+10001)%1000;
    i=t;
    for(i=1;i<=t;i++){

            scanf("%ld",&n);
            printf("Case #%d: %.3d\n",i,a[(int)n]);
    }
    fclose(stdin);
}

a[i]=(6*a[i-1]-4*a[i-2]+10001)%1000;行我知道会有整数溢出,但我不知道为什么通过添加10,000我得到了正确的答案。 我正在使用GCC编译器,其中sizeof(int)= 4

有人可以解释发生了什么吗?

1 个答案:

答案 0 :(得分:2)

首先,该行

a[i]=(6*a[i-1]-4*a[i-2]+10001)%1000;

实际上不会导致任何溢出,因为您将所有先前的值保持在1000以下。

其次,您是否考虑过如果6*a[i-1]-4*a[i-2]+1为负面会发生什么?模数运算符不必总是返回正值;它也可以返回负值(如果你要划分的东西本身是负数)。

通过添加10000,您可以确保无论以前的值是多少,该表达式的值都是正数,因此mod将给出正整数结果。

扩展第二点,这是C99规范的6.5.5.6:

  

当整数被分割时,/运算符的结果是代数   丢弃任何小数部分的商。如果商a / b是   可表示的,表达式(a / b)* b + a%b应等于a。

“丢弃”一词旁边的注释表明/“截断为零”。因此,对于第二个句子为真,a % ba为负时的结果本身必须为负。