http://acm.bjfu.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1440
题目意思简单的不能再简单,但是 以前从来没有接触过这一类型的题目,怎么做都感觉做不出来。 先引进几个知识点吧:
1——-快速幂模板:
原理: n*n*n*n…….n (m个n相乘);
设最后的结果为ans ,所以 ans=1*(m个n);
———————–|(循环)
| if(n是奇数),把一个n放进ans中,ans=n*(m-1个n);
| 这时 把 n 变成 n*n , 所以m变成 m/2;
| 所以等式就变成 ans=n*((m-1)/2个 n*n)
———————–| (循环) 直到 m=0停止
当然以上步骤一般是要取mod的,因为m会很大。
代码:
__int64 fast_pow(__int64n,__int64m)
{
__int64 ans=1;
while(m)
{
if(m%2==1)
{
ans*=n;
ans%=mod;
}
n*=n;
n%=mod;
m/=2;
}
return ans;
}
2—–矩阵相乘
矩阵 a * 矩阵b=a的行*b的列
如 |1 2 | | 5 6 | |1* 5+2 * 7 1*6+2 * 8 |
如 |3 4| * | 7 8 | =|3* 5+4* 7 3*6+4 * 8|
模板:
struct matr{
__int64 an[maxn][maxn] //(这里的maxn表示矩阵的行,列,不同情况 还需自己分析)
}base,ans; //(base 是拿来做快速幂的底数 ,ans是快速幂的结果)
matr mul(matr a,matr b)
{
matr c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
c.an[i][j]=0;
for(int k=0;k<2;k++)
c.an[i][j]+=a.an[i][k]*b.an[k][j];
c.an[i][j]%=maxn;
}
return c;
}
接下来就是矩阵快速幂了:
__int64 fast_mul(__int64 n)
{
(给base赋好初值)
(给ans赋好初值)
while(n)
{
if(n&1)
ans=mul(temp,ans) // 这里很重要:一定要搞清楚 temp在前 还是ans 在前, 之前就因为这出过错
n/=2;
base=mul(base,base);
}
return ans.an[i][j] //(这个i,j 因你给ans 赋初值的时候订,可能在任何位置)
}
这就写完了,再讲一下原理吧,和适用题目吧:
比如说 求n=100000000000 …… 0 的斐波那契数列 - -或者 a[n]=x*a[n-1]+y*a[n-2];
矩阵
|a[n] |………… |x y |……….. |a[n-1] |…… |x* a [n-1] + y*a[n-2] |
|a[n-1] | = | 1 0 | * |a[n-2] | = | 1*a[n-1] |
如此一来 求第n个 只需将 base进行n-1或者n-2 次幂运算即可(具体情况看赋给base,ans的初值)
using namespace std;
#define maxn 1000000007
struct matr
{
__int64 an[2][2];
}temp,ans;
matr mul(matr a,matr b)
{
matr c;
for(int i=0;i<2;i++)
for(int j=0;j<2;j++)
{
c.an[i][j]=0;
for(int k=0;k<2;k++)
c.an[i][j]+=a.an[i][k]*b.an[k][j];
c.an[i][j]%=maxn;
}
return c;
}
__int64 fast(__int64 n)
{
temp.an[0][0]=2;
temp.an[0][1]=2;
temp.an[1][0]=1;
temp.an[1][1]=0;
ans.an[0][0]=8;
ans.an[1][0]=3;
ans.an[0][1]=0;
ans.an[1][1]=0;
while(n)
{
if(n%2==1)
{
ans=mul(temp,ans);
}
n/=2;
temp=mul(temp,temp);
}
return ans.an[0][0];
}
int main() {
__int64 n;
//freopen("1.txt","r",stdin);
while(~scanf("%I64d",&n)){
if(n==1)
{
printf("3\n");
continue;
}
printf("%I64d\n",fast(n-2));
}
return 0;
}