您的位置:首页 > 其它

HDU 4291-A Short problem-循环节+矩阵快速幂

2016-08-03 18:48 381 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4291

 According to a research, VIM users tend to have shorter fingers, compared with Emacs users. 
  Hence they prefer problems short, too. Here is a short one: 
  Given n (1 <= n <= 10 18),
You should solve for 

g(g(g(n))) mod 10 9 + 7

  where 

g(n) = 3g(n - 1) + g(n - 2)

g(1) = 1

g(0) = 0

g(n)我们可以矩阵快速幂很快求得,但是关键是g(g(n))不好求,g(n)可能很大,不能直接mod,也即g(x)!=g(x%mod),mod=1e9+7。

打表可以发现 在mod=1e9+7下,g(x)=g(x%222222224),  然后把问题转为了 求g(g(g(n))%222222224),同理再次求循环节,把问题转为求:

g(g(g(n)%183120)%222222224)  ,这样就能分别三次快速幂求到答案

#include<cstdio>
#include<algorithm>
using namespace std;

const int N = 2;
long long mod;
struct Matrix
{
long long mat[2][2];
} ;
Matrix unit_matrix ;
long long n, k;

Matrix mul(Matrix a, Matrix b) //矩阵相乘
{
Matrix res;
for(int i = 0; i < k; i++)
for(int j = 0; j < k; j++)
{
res.mat[i][j] = 0;
for(int t = 0; t < k; t++)
{
res.mat[i][j] += a.mat[i][t] * b.mat[t][j];
res.mat[i][j] %= mod;
}
}

return res;
}

Matrix pow_matrix(Matrix a, long long m) //矩阵快速幂
{
Matrix res = unit_matrix;
while(m != 0)
{
if(m & 1)
res = mul(res, a);
a = mul(a, a);
m >>= 1;
}
return res;
}
Matrix get(long long n)
{
n--;
Matrix ori;
ori.mat[0][0]=1;
ori.mat[0][1]=0;
ori.mat[1][0]=0;
ori.mat[1][1]=0;
Matrix c;
c.mat[0][0]=3;
c.mat[0][1]=1;
c.mat[1][0]=1;
c.mat[1][1]=0;

Matrix ans = pow_matrix(c, n);
ans = mul(ori,ans);
return ans;
}
int main()
{
k=2;
int i, j, t;
//初始化单位矩阵 //类似快速幂的 ans=1; 如今是ans=单位矩阵
for(i = 0; i < 2; i++)
for(j = 0; j < 2; j++)
unit_matrix.mat[i][j] = 0;
for(i = 0; i < 2; i++)
unit_matrix.mat[i][i] = 1;
while(scanf("%lld",&n)!=EOF)
{
if (n%183120==0)
{
printf("0\n");
continue;
}
mod=183120;
Matrix ans=get(n);
mod=222222224;
if (ans.mat[0][0]==0)
{
printf("0\n");
continue;
}
ans=get(ans.mat[0][0]);
mod=(1e9)+7;
if (ans.mat[0][0]==0)
{
printf("0\n");
continue;
}
ans=get(ans.mat[0][0]);
printf("%lld\n", ans.mat[0][0]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: