hdu 5667 Sequence(矩阵快速幂+快速幂+费马小定理)(bestcoder# 80 1002)

3 篇文章 0 订阅
2 篇文章 0 订阅

Problem Description
     Holion August will eat every thing he has found.

     Now there are many foods,but he does not want to eat all of them at once,so he find a sequence.

fn=1,ab,abfcn1fn2,n=1n=2otherwise

     He gives you 5 numbers n,a,b,c,p,and he will eat  fn  foods.But there are only p foods,so you should tell him  fn  mod p.
 

Input
     The first line has a number,T,means testcase.

     Each testcase has 5 numbers,including n,a,b,c,p in a line.

    1T10,1n1018,1a,b,c109 , p  is a prime number,and  p109+7 .
 

Output
     Output one number for each case,which is  fn  mod p.
 

Sample Input
  
  
1 5 3 3 3 233
 

Sample Output
  
  
190
 

Source
 

Recommend
wange2014   |   We have carefully selected several similar problems for you:   5674  5673  5672  5671  5670 
 

题目大意:

        给定如题目中所述的公式,求出f(n)mod p,p是素数

解题思路:

        观察公式并手写几项下来,可以发现a^b总是一起出现并且只有指数发生了变化,所以设g(n)=log f(n)  (以a^b为底)

        根据公式:g(n)=1+c*g(n-1)+g(n-2) mod phi(p) (n>=2) 注意是phi(p),那么就可以用矩阵快速幂:(A^表示A的转置)

          (g(n),g(n-1),1)^=(c,1,1;  1,0,0;  0,0,1;)*(g(n-1),g(n-2),1)^ 根据g(1),g(2)的值算出需要的g(n)来。

        之后用快速幂(a^b)^g(n) mod p可以得出f(n)

        注:这种方法没有遇出题人t说的坑点

#include<stdio.h>
#include<stdio.h>
#include<iostream>
#define ll long long
#define rush() int t;scanf("%d",&t);while(t--)
using namespace std; 
struct mat { ll a[3][3]; };
ll mod,mod1;
mat operator * (mat a, mat b)
{
	mat ans;
	memset(ans.a, 0, sizeof(ans.a));
	for (int i = 0; i < 3; i++)
		for (int j = 0; j < 3; j++)
			for (int k = 0; k < 3; k++)
			{
				ans.a[i][j] += (a.a[i][k] * b.a[k][j]) % (mod-1);
				ans.a[i][j] %= mod-1;
			}
	return ans;
}
mat qpow(mat a, ll n)
{
	mat ans;
	memset(ans.a, 0, sizeof(ans.a));
	for (int i = 0; i < 3; i++)ans.a[i][i] = 1;
	while (n)
	{
		if (n & 1)ans = ans*a;
		a = a*a;
		n >>= 1;
	}
	return ans;
}
ll qpow(ll a, ll b)
{
	ll ans = 1;
	while (b)
	{
		if (b & 1)ans = (ans*a)%mod;
		a =(a*a)%mod;
		b >>= 1;
	}
	return ans;
}/*
ll phi(ll n)
{
	ll temp;
	temp = n;
	for (int i = 2; i*i <= n; i++)
	{
		if (n%i == 0)
		{
			while (n%i == 0) n = n / i;
			temp = temp / i*(i - 1);
		}
		if (n<i + 1)
			break;
	}
	if (n>1)
		temp = temp / n*(n - 1);
	return temp;
}*/
int main()
{
	rush()
	{
		mat tem;
		ll a, b, n,c;
		cin >> n >> a >> b >> c>>mod;
		ll k = qpow(a, b);
		if (n == 1) {cout<<'1'<<endl; continue; }
		else if (n == 2) { cout << k << endl; continue; }
		else
		{
			tem.a[0][0] = c;
			tem.a[0][1] = 1;
			tem.a[0][2] = 1;
			tem.a[1][0] = 1;
			tem.a[1][1] = 0;
			tem.a[1][2] = 0;
			tem.a[2][0] = 0;
			tem.a[2][1] = 0;
			tem.a[2][2] = 1;
			tem = qpow(tem, n - 2);//不能用phi(n-2)
			ll ans = ((tem.a[0][0]%(mod-1) + tem.a[0][2]%(mod-1)) % (mod-1) + mod-1) % (mod-1);
			ans = qpow(k, ans);
			cout << ans << endl;
		}
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值