zoukankan      html  css  js  c++  java
  • poj2720 Last Digits

    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) = bf(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

    2
    4
    7
    10
    10
    6
    3
    10
    7
    0
    

    Sample Output

    0065536
    000000
    4195387
    

    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 <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    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
    ");
            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("
    ");
            }
        }
    
        return 0;
    }
  • 相关阅读:
    《哈佛商业评论》2018正刊12期与增刊25期的点评
    《财经》2018年共30+1期的点评与摘抄
    4星|《人人都在说谎》:社会科学方面有趣的数据分析方法与结论
    3星|侯世达《我是个怪圈》:关于人类意识的各种哲学思辨
    虚拟机 SUSE Linux Enterprise Server 12 SP2 64
    虚拟机 CentOS7 64
    虚拟机 ubuntu 16.04
    虚拟机 windows xp sp3 原版
    C#实现控制Windows系统关机、重启和注销的方法
    日期时间设置 "2018-05-04T16:36:23.6341371+08:00" 格式
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8076433.html
Copyright © 2011-2022 走看看