Problem Description
作为CNCS的半壁江山,狗哥常常在宇宙中心邵阳眺望黄浦江,夜晚的星空总是迷人,有时候还能见到彗星滑落。
狗哥是幸运的,他在两秒钟内看到了十七颗彗星划过天际,作为打ACM的学者,自然不会有「稳定-1」情况。他开始研究彗星运动的轨迹,发现他们都遵照斐波那契螺旋线在运动着。
尤里卡!狗哥觉得这就是找寻「生命,宇宙和一切的终极答案」的精要所在,但是怎么表示呢?狗哥觉得求取斐波那契螺旋线经过的一个个方格的面积之和就是公式的表现。
例如下图,螺旋线每划过一个方格,都转过了四分之一圈。如果我们以四分之一圈为单位,那么我们用类似带分数的形式表示螺旋线转动的起点和终点。例如,0+0 到 0 + 1 意即从第一个方格转到第二个方格,划过了前两个方格,他们的面积之和为2(1+1)。同理,0+0 到 1+0 划过了前五个方格,他们的面积之和为40(1+1+4+9+25)。
但是聪明的狗哥需要一个程序去获得指定范围内的螺旋线面积之和,狗哥给了你一首「希望之花」的时间,而他需要利用这个时间去打出四暗刻单骑。如果你能完成这个程序,狗哥会封你为格拉摩根伯爵
Input
不定组数据。
首先输入一个整数Q,代表狗哥询问次数。
接下来Q行,每行四个整数a,b,c,d,代表狗哥想求 a+b 到 c+d 之间的螺旋线面积之和。
1<= Q <= 10000
0<= a,c <= 10000
0 <= b,d <= 3
结果对192600817取模。
Output
一个数字,表示螺旋线面积之和。
Sample Input
4
0 0 0 1
0 0 1 0
1 2 2 1
1 1 0 3
4
0 0 0 1
0 0 1 0
1 2 2 1
1 1 0 3
Sample Output
2
40
4791
98
2
40
4791
98
题意很难理解,下面我来理一下题意:首先看一下abcd的范围,0<= a,c <= 10000,0 <= b,d <= 3,也就是从0 0->0 1->0 2->0 3->1 0->1 1->1 2->1 3->……->1000 3,这样呢不好书写,我们可以转换一下计数的方式,将0 0 默认为1 ,0 1默认为2……所以就得到了a b的位置 x=a*4+b+1。之后正方形的边长就是斐波那契数列,面积就是边长×边长,题目的要求就是求ab到cd经过的正方形的面积之和。这时候就用到前缀和了,先将sum数组提前求出来,根据ab cd我们求出我们默认的位置x,y。答案就是sum[y]-sum[x-1].
注意1:一下当y<x的情况!!
注意2:因为斐波那契是成指数递增的,所以会出现超long long的情况,这时候就要考虑同余定理了,就在能取模的地方都取一下模。
注意3:当你写完程序时,一定要试一下这个样例9999 1 9999 1,如果答案是负数,那请你看下面的解释:因为是对192600817取模,有一种情况是x,y在192600817两边,挨的很近,那么就会出现sum[y]%MM-sum[x-1]%MM<0的情况,这时候要特判一下,在加一个192600817。
AC代码:
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <deque>
#include <stack>
using namespace std;
typedef long long ll;
const int MAX=40010;
const int MM=192600817;
deque <ll> dq;
ll ans[MAX]= {0};
ll ans2[MAX]= {0};
ll sum[MAX]= {0};
void f()
{
ll i;
ans[1]=1;
ans[2]=1;
for(i=3; i<=MAX-1; i++)
ans[i]=(ans[i-1]%MM+ans[i-2]%MM)%MM;
for(i=1; i<=MAX-1; i++)
ans2[i]=((ans[i]%MM)*(ans[i]%MM))%MM;
for(i=1; i<=MAX-1; i++)
sum[i]=(ans2[i]%MM+sum[i-1]%MM)%MM;
}
int main()
{
ll t,i,j,n,m,a,b,c,d,x,y;
f();
while(cin>>t)
{
for(i=0; i<t; i++)
{
cin>>a>>b>>c>>d;
x=a*4+b+1;
y=c*4+d+1;
if(y>=x)
{
ll anss=(sum[y]%MM-sum[x-1]%MM)%MM;
if(anss<0)//避免出现注意3里的情况。
cout<<anss+MM<<endl;
else
cout<<anss<<endl;
}
else
{
ll anss=(sum[x]%MM-sum[y-1]%MM)%MM;
if(anss<0)
cout<<anss+MM<<endl;
else
cout<<anss<<endl;
}
}
}
return 0;
}
希望对你们有所帮助。