hdu 2814 Interesting Fibonacci

题目:hdu 2814 Interesting Fibonacci

题意:求F(a^b)^(F(a^b) ^ (n-1))%c  (F(n)表示斐波那契数列,1<=c<=300,a,b,n都是2^64的数,用unsigned long long存)

思路:指数循环节和斐波那契数列循环节

我是不会跟你说这题我WA,TLE,RE了二三十次了。。。然后足足AC了七遍。。

F(n)%c 的情况,根据斐波那契数列的循环节求出来,做法跟12年四川现场赛那题一样。

式子中存在两个F(a^b) ,对于第一个,求对于mod c的循环节,第二个根据指数循环节,求mod phi(c)的循环节,然后其他就是乱七八糟的求快速幂,求斐波那契数列。

这题,TLE若干次之后,发现因为c的范围只有300,所以我们可以先预处理300以内数字的循环节。

然后,经历了若干次RE,原因是除0了(我除你妹的0,我压根就没粗线过0)。

意外的将题目数据改成17 18446744073709551615 1998 2程序直接跪了,看来问题在于 mod 2 的那,找了下别人的代码,试了这组数据,照样跪了,但是为喵别人能AC 呢 (之后我AC的代码输出的答案是 1)

所以呢,在经历无数次WA之后,貌似找到问题所在了,模1的情况答案输出当然是0,模2的暂时不知道,想一想欧拉值等于1的只有2,所以当c=2的时候,F的幂的部分就mod 1直接等于0,所以不管底数多少,答案就是1了,解释了我刚才说的样例。

然后对于前面的预处理 smod[1]=1 这个得加上(虽然我不知道什么时候会出现这种数据,但是不加这句话,就是会RE)


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
typedef unsigned __int64 LL;
struct Matrix
{
	LL m[3][3];
}E, D;
LL Pow(LL a, LL b, LL mod)
{
	LL ans = 1;
	while (b)
	{
		if (b & 1)
		{
			b--;
			ans = (ans*a)%mod;
		}
		else
		{
			b /= 2;
			a = (a*a)%mod;
		}
	}
	return ans;
}
void init()
{
	for (int i = 1; i <= 2; i++)
		for (int j = 1; j <= 2; j++)
		{
			D.m[i][j] = 1;
			E.m[i][j] = (i == j);
		}
		D.m[2][2] = 0;
}
Matrix Multi(Matrix A, Matrix B, LL mod)
{
	Matrix ans;
	for (int i = 1; i <= 2; i++)
		for (int j = 1; j <= 2; j++)
		{
			ans.m[i][j] = 0;
			for (int k = 1; k <= 2; k++)
				ans.m[i][j] = (ans.m[i][j] + A.m[i][k] * B.m[k][j])%mod;
		}
		return ans;
}
Matrix Pow(Matrix A, LL k, LL mod)
{
	Matrix ans = E;
	while (k)
	{
		if (k & 1)
		{
			k--;
			ans = Multi(ans, A, mod);
		}
		else
		{
			k /= 2;
			A = Multi(A, A, mod);
		}
	}
	return ans;
}
LL Fib(LL n, LL mod)
{
	return Pow(D, n, mod).m[2][1];
}
long long euler(long long x)
{
	long long i, res = x;
	for (i = 2; i*i <= x; i++)
		if (x%i == 0)
		{
			res = res / i*(i - 1);
			while (x%i == 0)
				x /= i;
		}
		if (x > 1)
			res = res / x*(x - 1);
		return res;
}
LL s_mod(LL n)
{
	LL a1 = 0, a2 = 1, a3 = 1, tmp, ans = 1;
	while (a2 != 0 || a3 != 1)
	{
		ans++;
		tmp = (a2 + a3)%n;
		a2 = a3;
		a3 = tmp;
	}
	return ans;
}
LL smod[305];

int main()
{
	init();
	smod[1] = 1;
	for (int i = 2; i <= 300; i++)
		smod[i] = s_mod(i);
	LL a, b, n;
	int c;
	int t;
	scanf("%d", &t);
	LL mod1, mod2, tmp, cnt, ans, eul;
	for (int cas = 1; cas <= t; cas++)
	{
		scanf("%I64u%I64u%I64u%d", &a, &b, &n, &c);
		if (c == 1)
		{
			printf("Case %d: 0\n", cas);
			continue;
		}
		mod1 = smod[c];
		eul = euler(c);
		mod2 = smod[eul];
		tmp = Pow(a%mod1, b, mod1);
		tmp = Fib(tmp, c);
		cnt = Pow(a%mod2, b, mod2);
		cnt = Fib(cnt, eul);
		cnt = Pow(cnt, n - 1, eul);
		cnt += eul;
		ans = Pow(tmp, cnt, c);
		printf("Case %d: %I64u\n", cas, ans);
	}
	//system("pause");
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值