题目: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;
}