Last Digits
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2378 | Accepted: 501 |
Description
Exponentiation of one integer by another often produces very large results. In this problem, we will compute a function based on repeated exponentiation, but output only the last n digits of the result. Doing this efficiently requires careful thought about how to avoid computing the full answer. Given integers b, n, and i, we define the function f(x) recursively by f(x) = b f(x-1) if x > 0, and f(0)=1. Your job is to efficiently compute the last n decimal digits of f(i).
Input
The input consists of a number of test cases. Each test case starts with the integer b (1 <= b <= 100) called the base. On the next line is the integer i (1 <= i <= 100) called the iteration count. And finally, the last line contains the number n (1 <= n <= 7), which is the number of decimal digits to output. The input is terminated when b = 0.
Output
For each test case, print on one line the last n digits of f(i) for the base b specified. If the result has fewer than n digits, pad the result with zeroes on the left so that there are exactly n digits.
Sample Input
2471010631070
Sample Output
00655360000004195387
Source
题目大意:定义F(i) = b^F(i - 1).F(0) = 1,现在要求F(i)的后n位.
分析:这道题非常毒瘤......很显然这道题要用欧拉定理解决.对于取后n位数,mod 10^n就可以了.这个10^n比较大,意味着要求出1~10^7之间的数的欧拉函数值.线性筛打了一发,发现T掉了.
后来想了一个非常奇怪的方法:每次我把n固定为7,也就相当于取了答案的后7位,最后在这后7位中取后n位就好了嘛.这样每次要用到的欧拉函数都是固定的:10000000,4000000,1600000,640000,256000,这都是比较大的欧拉函数,剩下的30w以内的用线性筛处理就好了.
这样还是有点问题,因为是多组数据,可能会有很多重复的数出现,所以需要记忆化一下,这样就解决了T的问题.
如果只是这样做最后会WA掉,因为递归用的欧拉定理是在指数大于模数的欧拉函数时才会成立.小于的话必须直接算.可是在递归的过程中不太容易及时比较大小.于是我想着每次递归的时候将当前的数给算出来再比大小,结果T掉了.解决的方法是分类讨论.因为F函数的增长速度超级快,如果i = 2,那么只有当b ≤ 6的时候才需要特殊考虑. i = 3,4,考虑b = 2的情况,剩下的都会超过10000000.结合上述所有的优化,就能通过这道题了.
#include#include #include #include using namespace std;typedef long long ll;const int maxn = 300000;ll b,n,p,tot,num[10],cnt,ans,f[110][110];int prime[1000010],phi[10000010];bool vis[10000010];ll qpow(ll a,ll b,ll mod){ ll res = 1; while(b) { if (b & 1) res = (res * a) % mod; b >>= 1; a = (a * a) % mod; } return res;}void init(){ phi[1] = 1; phi[10000000] = 4000000; phi[4000000] = 1600000; phi[1600000] = 640000; phi[640000] = 256000; for (int i = 2; i <= maxn; i++) { if (!vis[i]) { prime[++tot] = i; phi[i] = i - 1; } for (int j = 1; j <= tot; j++) { ll t = prime[j] * i; if (t > maxn) break; vis[t] = 1; if (i % prime[j] == 0) { phi[t] = phi[i] * prime[j]; break; } phi[t] = phi[i] * (prime[j] - 1); } }}ll solve(ll dep,ll mod){ if (dep == 1) return b; if (mod == 1) return 0; if (f[b][dep] == -1) { ll temp = phi[mod]; ll tt,temp2 = solve(dep - 1,temp); tt = qpow(b,temp2 + temp,mod); return f[b][dep] = tt; } return f[b][dep] % mod;}int main(){ memset(f,-1,sizeof(f)); init(); while (~scanf("%lld",&b) && b) { cnt = 0; memset(num,0,sizeof(num)); scanf("%lld%lld",&n,&p); if (p == 0) printf("0\n"); else { ll cur = p; p = qpow(10,p,100000010); if (f[b][n] != -1) ans = f[b][n]; else { if (n == 2 && b <= 6) ans = qpow(b,b,10000000); else if (n == 3 && b <= 3) ans = qpow(b,qpow(b,b,10000000),10000000); else if (n == 4 && b == 2) ans = qpow(b,qpow(b,qpow(b,b,10000000),10000000),10000000); else ans = solve(n,10000000); f[b][n] = ans; } while (ans) { num[++cnt] = ans % 10; ans /= 10; } for (int i = cur; i >= 1; i--) printf("%d",num[i]); printf("\n"); } } return 0;}