00013:郭姐散步(二)
总时间限制:
10000ms
内存限制:
32768kB
描述
The first lady of our team is GuoJie, GuoJie likes walking very much.
Today GuoJie walks from the original point (0, 0), everytime he(may beshe?) can go up or left or right a step.
But she can't go back the point where she have visited.
For example, if he goes up a step, she will be at (1, 0) and she nevercomes back the point.
Now, if she can walk n(n <= 1e18) steps, can you find howmany ways she can walk? the result mod 1e9 + 7.
输入
There will be T (T <= 100000) cases,each case will input a n.
输出
For each group of input integers youshould output how many ways GuoJie can walk in one line, and with one line ofoutput for each line in input.
样例输入
1
2
样例输出
7
这道题目其实规律早就找出来了,数据量小的时候直接用递推式也可以做,但是这道题T和n都很大,所以要多加注意才行。
直接用递推式,要想推到1e18,实在是不大可能。所以这道题的正解是用矩阵快速幂。
矩阵快速幂应用的条件就是有递推式的时候,我们就必定可以转化为矩阵乘法来表示。
按照矩阵快速幂的原理,他会在n转化为二进制的为1的地方进行一次乘法。那么1e18,最多也就是2的63次方,也就是我们只需要进行63次运算即可得到答案,是不是很快呢?比直接用递推式算到1e18不知道快了多少倍。
由于这道题目T很大,达到了10万次,代码中有一个地方写不好的话,都有可能会被卡常,所以这是要注意的。
代码如下:
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
const long long mod = 1e9+7;
struct matrix
{
long long a[2][2];
}origin,res;
matrix multiply(matrix x,matrix y)
{
matrix temp;
memset(temp.a,0,sizeof(temp.a));
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
for(int k=0;k<2;k++)
temp.a[i][j] = (temp.a[i][j] + x.a[i][k] * y.a[k][j]) % mod;
return temp;
}
void init()
{
// memset(res.a,0,sizeof(res.a));
res.a[0][0] = 3;
res.a[0][1] = 1;
res.a[1][0] = 0;
res.a[1][1] = 0;
// memset(origin.a,0,sizeof(origin.a));
origin.a[0][0] = 2;
origin.a[0][1] = 1;
origin.a[1][0] = 1;
origin.a[1][1] = 0;
}
void calc(long long n)
{
while(n)
{
if(n & 1)
res = multiply(res, origin);
n >>= 1;
origin = multiply(origin, origin);
}
printf("%lld\n", res.a[0][0]);
}
int main()
{
int T;
long long N;
scanf("%d",&T);
while(T--)
{
scanf("%lld", &N);
init();
if(N <= 0)
printf("0\n");
else if(N == 1)
printf("3\n");
else
calc(N - 1);
}
return 0;
}
在矩阵乘法那里有一个乘法运算,为了防止乘法运算后再加上矩阵自己本身爆long long范围,其实应该用a * b % mod = ((a % mod) * (b % mod)) % mod,但是想了想,相对于long long而言,1e9+7其实是一个很小的数字,所以并不会爆long long才对。于是没有那上面那规律,直接写,也能过。