zoukankan      html  css  js  c++  java
  • K次方(即求n^k的前三位与后三位)

    题目来源,多校联合赛: http://acm.hdu.edu.cn/diy/contest_showproblem.php?cid=16820&pid=1002(重开,密码:52acm8)

    注意:貌似过了这段时间不能提交了的说。。。。。。

    K次方

    Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)
    Total Submission(s) : 31   Accepted Submission(s) : 15

    Font: Times New Roman | Verdana | Georgia

    Font Size:  

    Problem Description

    所有在程式设计已经有点经验的人都知道,当k很大时你无法完整的表达出n k。例如: C语言的函数 pow(123456,455)能够用double资料型态来表达,但是你却无法得到所有正确的数字。然而,若是能知道一些最左边(leading)和最右边(trailing)数字的话,也可稍微得到一些满足。

    Input

    输入的第一行有一个整数T(T < 1001),代表有几组测试资料。接下来的T行,每行有2个正整数n和k。n可以用32位元的整数表达,而k<10000001。

    Output

    每组测试资料输出一行,输出LLL...TTT的样式。其中LLL代表n k的最左边3个数字,TTT代表n k的最右边3个数字。例如123456 2 = 15241383936,所以你应该输出152...936。
    你可以假设n k至少有6位数。

    Sample Input

    3
    123456 1
    123456 2
    2100000056 67333

    Sample Output

    123...456
    152...936
    982...016

    Author

    shenlizhong
    感谢kb神的解释:
    对于这种大数如果没有像标程一样,转化为log型的,就一定要注意精度问题了。
    比赛时用long long 一直错啊,然后取模的精度也出问题了,后来kb神说用double就对了~~~~~~
    代码一:
    比赛完后,根据标程改的,要注意思路什么的都在里面了
    //巧妙的思想,后三位用幂取模可以求出注意补0,
    //总位数可利用t=k*log10((double)n)+1 向上取整求出,
    //前三位根据方程head=n^k/(10^(t-3))求出
    //注意:1求一个数的位数就是把它对10取对数,然后加1即可(科学计数法)
    //      2求lnx为log(x);求lgx为log10(x);求以n为底的就是logn();(还好kb神提醒了这一点。。。)
    //      3注意重载函数log的调用(强制类型转换,并且加上头文件#include<math.h>):
    //       “long double log(long double)”
    //       “float log(float)”
    //       “double log(double)”
    //推荐一道求n的阶乘的位数的题目hdu 1018 (斯特林公式)
    
    //31 MS	276 KB	Visual C++
    #include<iostream>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    int pow_mod(int a,int n,int m)//就是那个很快的求a^n%m的快速幂的函数,可以去看下我的那个快速幂模板的博客
    {
        if(n==0)
           return 1%m;
        int ret=1;
        while(n>0)
        {
            if(n&1)
            {
                ret=(ret*a)%m;
            }
            n>>=1;
            a=(a*a)%m;
        }
        return ret;
    }
    int main()
    {
        int T,n,k;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&k);
            int t=k*log10((double)n)+1;//求n^k的位数,科学计数法思想。。。
            int head,tail;
            tail=pow_mod(n%1000,k,1000);
            for(head=100;log((double)head)<=k*log((double)n)-(t-3)*log((double)10);head++);//注意这里的分号';',区别于我们平时的for()循环,中间的表示head<=n^k/10^(t-3);数学问题毕竟是要写在纸上才看的懂的
            head--;//因为前面的for()中多加了一位,所以这里head减去一位
            printf("%3d...%03d\n",head,tail);
        }
        return 0;
    }
    
    
    代码二:看了kb神的代码后,改的我比赛时错的代码
    /*
    float的范围为-2^128~+2^128,也即-3.40E+28~+3.40E+38;
    double的范围为-2^1024~+2^1024,也即-1.79E+308~+1.79E+308.
    */
    //更正的代码(改成double就对了。。。long long桑不起啊):0 MS	260 KB	Visual C++	
    #include<stdio.h>
    const double mod=1e20;//精度问题桑不起啊!!!
    const int m1=1000;
    int pow1_mod(__int64 m,int n)//求m^n%1000的快速幂函数,不解释。。。(求后三位)
    {
        int b=1;
        m%=m1;
    	if(n==1)
    		return m;
        while(n>0)
        {
            if(n&1)
            {
                b=(b*m)%m1;
            }
            n=n>>1;
            m=(m*m)%m1;
        }
        return b;
    }
    
    int pow2_mod(__int64 m,int n)//截取前面很长的一段(那么后面的数对于前三位的影响就很小了,精度问题永远都是硬伤啊),然后不停的相乘,不停的取模(求前三位)
    {
        double b=1;
        double temp=(double)m;
        while(temp>mod)
          temp/=10;
        while(n>0)
        {
            if(n&1)
            {
                b=(b*temp);
                while(b>mod)
                  b/=10;
            }
            n=n>>1;
            temp=temp*temp;
            while(temp>mod)
              m=temp/=10;
        }
        while(b>=m1)
         b/=10;
        return (int)b;
    }
    
    int main()
    {
        int test;
        __int64 n;
        int k;
        int ans1,ans2;
        while(scanf("%d",&test)!=EOF)
        {
            while(test--)
            {
               scanf("%I64d%d",&n,&k);
               ans1=pow2_mod(n,k);
               ans2=pow1_mod(n,k);
               printf("%d...%03d\n",ans1,ans2);
            }
        }
        return 0;
    }

    代码三:(来自kb神原创,用double秒掉的,无限膜拜强大的kb神啊大笑
    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    const double qq=1e20;
    int solve1(long long a,int n)
    {
        a%=1000;
        int temp=a;
        int ret=1;
        while(n)
        {
            if(n&1)
            {
                ret*=temp;
                ret%=1000;
            }
            temp*=temp;
            temp%=1000;
            n>>=1;
        }
        return ret%1000;
    }
    int cal2(long long a,int n)
    {
        double ret=1;
        double temp=(double)a;
        while(n)
        {
            if(n&1)
            {
                ret*=temp;
                while(ret>=qq)ret/=10;
            }
            temp*=temp;
            while(temp>=qq)temp/=10;
            n>>=1;
        }
        while(ret>=1000)ret/=10;
        return (int)ret;
    }
    
    int main()
    {
       // freopen("A.in","r",stdin);
       // freopen("A.out","w",stdout);
       // printf("%lf\n",qq);//高精度,桑不起啊
        long long a;
        int n;
        int T;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%I64d%d",&a,&n);
           // printf("%d\n",cal2(a,n));
            printf("%d...%03d\n",cal2(a,n),solve1(a,n));
        }
        return 0;
    }


    代码四:改的标程的代码(坑爹的标程,都不给个能AC的代码)不过还是很膜拜标程的log使用了

    //更正后的标程46 MS	276 KB	Visual C++
    #include<iostream>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    int pow_mod(int a,int n,int m)
    {
        if(n==0)
        return 1%m;
        long long x=pow_mod(a,n/2,m);
        x=(x*x)%m;
        if(n%2)
        x=(x*a)%m;
        return (int)x;
    }
    int main()
    {
        int T,n,k;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&k);
            int t=k*log10((double)n)+1,head,tail;
            tail=pow_mod(n%1000,k,1000);
            for(head=100;log((double)head)<=k*log((double)n)-(t-3)*log((double)10);head++);
            head--;
            printf("%3d...%03d\n",head,tail);
    
        }
        return 0;
    }
    




  • 相关阅读:
    Ldap遇到了事务管理问题
    Spring-Ldap连接Ldap及简单的增删查改
    枚举与数组的使用
    GDI_TCanvas
    获取鼠标当前位置的相对坐标、模拟鼠标点击事件
    绘制不规则图片、窗体与图形
    Message使用
    泛型_Tlist存储对象
    控件Owner和Parent的区别
    鼠标拖放
  • 原文地址:https://www.cnblogs.com/freezhan/p/2776489.html
Copyright © 2011-2022 走看看