题意:
Given n (1 <= n <= 1018), You should solve for
g(g(g(n))) mod 109 + 7
where
g(n) = 3g(n - 1) + g(n - 2)
g(1) = 1
g(0) = 0
分析:
这个递推关系可以用矩阵快速幂来解决,但是这个题的问题是mod很大,会爆long long 并且超时的。那么这就需要一些特技了。
于是看到大家都用的循环节,但是网上对为什么要这么取循环节却都模糊或者答非所问,大概都不太晓得,知道可以A提就可以了,或者是大神们觉得这些小儿科的东西不用提上来讲。我的理解是这是一个自变量与函数值之间的关系的一种利用吧,比如g(x)%mod, 随着g(x)的增大,总有一天会大过mod,然后又被变成0,重新开始,所以g(x)是循环的,它的循环节是mod,那么g(x)的变化是随着x的变化而变化的,那么g(x)循环,x 也会相应的有循环节(这是根据函数的性质来决定的,不是所有的函数都有循环节,起码这种类似斐波那契数列的函数可以),也就是说当x到达一个值n时,g(x)==mod,x大于n之后g(x)也大过mod,那么n+1和之前的1效果是一样的,所以x的循环节就是n. 在这个题中有多个循环节是因为函数的嵌套,那么最外层求得的自变量的循环节mod1就是里面嵌套函数的函数值的循环节,依次递推,找到三个循环节。
#include <iostream>
#include <cstdio>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
#define read freopen("q.in","r",stdin)
#define LL long long
LL mod ;
struct Matri
{
LL mat[2][2];
//Matri(){memset(mat,0,sizeof(mat));}
void init()
{
mat[0][1]=mat[1][0]=0;
mat[0][0]=mat[1][1]=1;
}
};
Matri mul(Matri a,Matri b)
{
Matri res;
int i,j,k;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
res.mat[i][j]=0;
for(k=0;k<2;k++)
{
res.mat[i][j]=(res.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod)%mod;
}
}
}
return res;
}
Matri exp(Matri a,LL n)
{
Matri res;
res.init();
if(n==0)return res;
if(n==1)return a;
while(n)
{
if(n&1)res=mul(res,a);
a=mul(a,a);
n>>=1;
}
return res;
}
int main()
{
Matri B;B.mat[0][0]=3;B.mat[0][1]=1;B.mat[1][0]=1;B.mat[1][1]=0;
// circle();
// cout<<mod<<"??£í£í£í£í£í??"<<endl;
LL n;
while(~scanf("%I64d",&n))
{
if(n==0)
{
puts("0");
continue;
}
if(n==1)
{
puts("1");
continue;
}
mod=183120L;
Matri res=exp(B,n-1);
n=res.mat[0][0];
if(n!=0 && n!=1)
{
mod=222222224L;
res=exp(B,n-1);
n=res.mat[0][0];
}
if(n!=0 && n!=1)
{
mod=1000000007L;
res=exp(B,n-1);
}
cout<<res.mat[0][0]<<endl;
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-08 17:30:50