指数模上一个小的合数.
题目描述:
轮回:定义递归函数f(x) = bf(x-1) if x > 0, and f(0)=1,给出b和x,求f(x)的最后n位数。
题解:
x^y%p,如果p是质数,那么就有x^p-1=1(modp),指数对p-1取模就行了.但是p不是质数,那么如果x和p互质,可以用欧拉定理:x^phi(p)=1(modp),如果x和p也不互质,那么就是本题,x^(y) = x^(y%phi(p) + phi(p))(modp). 其中y有大于某个数num(x).
小技巧1:mod只用选7次方.因为结果再模就行了.
小技巧2:定义一个limit值,1e7,高于这个就是-1了.那么就用公式递归的往下算.小于limit,就用快速幂
小技巧3:打标用cache
小技巧4:format[]+printf
重点:
欧拉定理拓展
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(int i = a;i < b;i++)
#define REP_D(i, a, b) for(int i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const int maxn = 100 + 10;
const int key = 1e7;
const int MAXP = 700000;
int f[maxn][maxn];
int fb[maxn][maxn];
int cache[maxn][maxn];
int p[MAXP];
int pn;
int vis[key+100];
int phi(int x)
{
int xx = x;
int ans = x;
int limit = sqrt(x*1.0)+1e-10;
for(int i = 0; p[i]<=limit; i++)
{
if(x%p[i]==0)
{
ans = ans/p[i]*(p[i]-1);
while(x%p[i]==0)
{
x /= p[i];
}
}
}
if(x != 1)
{
ans = ans/x*(x-1);
}
return ans;
}
int pow_mod(int x, int n, int m)
{
if(n==0)
{
int t = 1;
return t;
}
int xx = ((ll)x*(ll)x)%m;
int nn = n/2;
int res = pow_mod(xx, nn, m);
if(n%2==1)
{
res = ((ll)res*(ll)x)%m;
}
return res;
}
void getFb()
{
REP_D(i, 0, 100)
{
fb[i][1] = 1;
}
REP_D(b, 2, 100)
{
fb[0][b] = 1;
fb[1][b] = b;
REP_D(i, 2, 100)
{
int limit= log(key)/log(b);
if(fb[i-1][b]>limit || fb[i-1][b]==-1)
{
fb[i][b]=-1;
}
else
{
fb[i][b] = pow_mod(b, fb[i-1][b], key);
}
// if(i==1)
// printf(" i is %d b is %d fb is %d\n", i, b, fb[i][b]);
}
}
}
void eulr()
{
pn = 0;
CLR(vis);
//phi[1] = 0;
REP_D(i, 2, 10000)
{
if(!vis[i])
{
p[pn++] = i;
//phi[i] = i - 1;
}
for(int j = 0; j<pn&&p[j]*i<=key; j++)
{
int tmp = i*p[j];
vis[tmp] = 1;
if(i%p[j])
{
;
}
else
{
break;
}
}
}
//printf("%d------\n", pn);
}
int getf(int b, int i, int mod)//计算
{
if(mod == 1)//边界情况,特别要注意!!
return 0;
int res;
// if(i<= 0)
// {
// printf(" i is %d b is %d fb is %d\n", i, b, fb[i][b]);
// }
if(fb[i][b]==-1)//不能直接用,递归算
{
int p = phi(mod);//下一个需要提前取模,因为当前的算不出来
int t = getf(b, i-1, p);
t += p;
res=pow_mod(b, t, mod);//小的快速幂
}
else
{
res = fb[i][b]%mod;//可以直接算
}
return res;
}
void solve()
{
eulr();
getFb();
}
void calcu(int i, int b)
{
int m = 7;
int mod = pow(10, m) + 0.1;
f[i][b] = getf(b, i, mod);
cache[i][b] = 1;
//printf("i is %d b is %d\n", i, b);
}
int main()
{
// freopen("5Ein.txt", "r", stdin);
//freopen("5Eout.txt", "w", stdout);
solve();
CLR(cache);
int b;
while(scanf("%d", &b)==1&&b!= 0)
{
int i, n;
scanf("%d%d", &i, &n);
char format[30] = "%00d\n";
format[2] += n;
int temp = pow(10, n) + 0.1;
if(cache[i][b]!=0)
printf(format, f[i][b]%(temp));
else
{
if(b != 1)
calcu(i, b);
else
f[i][b] = 1;
printf(format, f[i][b]%(temp));
}
}
return 0;
}