题目链接:戳我~
题目描述 Description
斐波那契数列:f[0]=0,f[1]=1,f[i]=f[i-1]+f[i-2]
求f[1]*f[1]+f[2]*f[2]+…+f[n]*f[n]的值
输入描述 Input Description
仅一行,一个正整数n
输出描述 Output Description
仅一行一个数,即所求的值,由于结果可能很大,需对1,000,000,007取模
样例输入 Sample Input
3
数据范围及提示 Data Size & Hint
对于100‰的数据,n<=1,000,000=10^6
然而:
对于200‰的数据,n<=9,000,000,000,000,000,000=9*10^18
对于500‰的数据,n<=10^500
对于1000‰的数据,n<=10^50000
做此题一定要注意,那是千分号!!!,不是百分号!!!
当时看10W递推吧=-= 结果10分……
这个题目用到斐波那契数列的一个性质:前n项fibonacci的平方和 等于 第fib[n]*fib[n+1]。
这个性质你要是说不懂那自然是正常的,你要是不懂还不打表找规律那就不正常了……
知道了这个性质之后我们就可以快速求前n项fib的平方和了,这时候看100的数据范围给定n <= 10^50000,一看就知道取膜乱搞,利用手动读入的优势边读边取膜就可以啦~(开始我居然想只读后10位……)
但是就算是10亿以内递推也不行,用矩阵乘法和快速幂优化一下就可以啦~
这里还推荐大家多去矩阵67的博客看看,特别棒~戳
代码实现:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<deque>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod = 1000000007ll;
struct juzhen{
int n,m;
int num[3][3];
juzhen(){memset(num,0,sizeof(num)); n = 0,m = 0;};
};
juzhen operator * (juzhen a,juzhen b)
{
juzhen ans;
ans.n = a.n,ans.m = b.m;
for(int i = 1;i <= a.n;i ++)
{
for(int j = 1;j <= b.m;j ++)
{
for(int k = 1;k <= a.m;k ++)
{
ans.num[i][j] = (ans.num[i][j]%mod + (a.num[i][k]%mod)*(b.num[k][j]%mod)%mod)%mod;
}
}
}
return ans;
}
juzhen fib,tmp;
void ksm(ll b)
{
while(b)
{
if(b & 1) fib = fib * tmp;
tmp = tmp * tmp;
b >>= 1;
}
}
void RD(ll &x)
{
x = 0;
char c;
c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = ((x << 1) + (x << 3) + c - '0')%(mod+1),c = getchar();
}
ll n,ou;
int main()
{
/* int t;
cin>>t;
while(t--)
{*/
fib.num[1][1] = 1; fib.num[1][2] = 0;
fib.n = 1,fib.m = 2;
tmp.num[1][1] = tmp.num[1][2] = tmp.num[2][1] = 1;
tmp.n = tmp.m = 2;
RD(n);
ksm(n);
// cout<<fib.num[1][1]<<" "<<fib.num[1][2]<<endl;
ou = (fib.num[1][1]%mod*fib.num[1][2]%mod)%mod;
cout<<ou<<endl;;
// }
return 0;
}