uva 10275 Guess the Number!

Guess the Number!
题意:给一个大数,问能否写成n^n。如果能,输出n,否则输出-1。
思路:除了1^1=1,2^2=4特殊外,其它数n^n所得到的数具有唯一的位数。这样可通过所给的大数的位数确定是哪个数,然后求n^n和所给的大数比较就行了。
n^n用快速幂来弄,然后用傅立叶大数相乘模板卡过去了,这个方法可能不是正解。
View Code
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<map>
using namespace std;
map<int,int>as;
typedef struct vir{
        double re,im;
        vir(){}
        vir(double a,double b){re=a;im=b;}
        vir operator +(const vir &b){ return vir(re+b.re,im+b.im);}
        vir operator -(const vir &b){ return vir(re-b.re,im-b.im);}
        vir operator *(const vir &b){ return vir(re*b.re-im*b.im,re*b.im+b.re*im);}
}vir;
vir x1[1000005],x2[1000005];
const double Pi = acos(-1.0);
void change(vir *x,int len,int loglen)
{
        int i,j,k,t;
        for(i=0;i<len;i++)
        {
                t = i;
                for(j=k=0;j<loglen;j++,t>>=1)
                        k = (k<<1)|(t&1);
                if(k<i)
                {
                        vir wt =  x[k];
                        x[k] = x[i];
                        x[i] = wt;
                }
        }
}
void fft(vir *x,int len,int loglen)
{
        int i,j,t,s,e;
        change(x,len,loglen);
        t = 1;
        for(i=0;i<loglen;i++,t<<=1)
        {
                s = 0;
                e = s + t;
                while(s<len)
                {
                        vir a,b,wo(cos(Pi/t),sin(Pi/t)),wn(1,0);
                        for(j=s;j<s+t;j++)
                        {
                                a = x[j];
                                b = x[j+t]*wn;
                                x[j] = a + b;
                                x[j+t] = a - b;
                                wn =wn*wo;
                        }
                        s = e+t;
                        e = s+t;
                }
        }
}

void dit_fft(vir *x,int len,int loglen)
{
        int i,j,s,e,t=1<<loglen;
        for(i=0;i<loglen;i++)
        {
                t>>=1;
                s=0;
                e=s+t;
                while(s<len)
                {
                        vir a,b,wn(1,0),wo(cos(Pi/t),-sin(Pi/t));
                        for(j=s;j<s+t;j++)
                        {
                                a = x[j]+x[j+t];
                                b = (x[j]-x[j+t])*wn;
                                x[j] = a;
                                x[j+t] = b;
                                wn = wn*wo;
                        }
                        s = e+t;
                        e = s+t;
                }
        }
        change(x,len,loglen);
        for(i=0;i<len;i++)
                x[i].re/=len;
}
void cal(char a[],char b[],char c[])//傅立叶大数相乘模板a*b=c
{
        int i,len1,len2,t,over,len,loglen;
        len1 = strlen(a)<<1;
        len2 = strlen(b)<<1;
        len = 1;
        loglen = 0;
        while(len<len1)
        {
            len<<=1;
            loglen++;
        }
        while(len<len2)
        {
            len<<=1;
            loglen++;
        }
        for(i=0;a[i]!='\0';i++)
        {
            x1[i].re = a[i]-'0';
            x1[i].im = 0;
        }
        for(;i<len;i++)
            x1[i].re = x1[i].im = 0;
        for(i=0;b[i]!='\0';i++)
        {
            x2[i].re = b[i]-'0';
            x2[i].im = 0;
        }
        for(;i<len;i++)
            x2[i].re = x2[i].im = 0;
        fft(x1,len,loglen);
        fft(x2,len,loglen);
        for(i=0;i<len;i++)
            x1[i] = x1[i]*x2[i];
            dit_fft(x1,len,loglen);
        for(i=(len1+len2)/2-2,over=loglen=0;i>=0;i--)
        {
            t = x1[i].re + over + 0.5;
            a[loglen++] = t%10;
            over =  t/10;
        }
        while(over)
        {
                a[loglen++] = over%10;
                over /= 10;
        }
        for(loglen--;loglen>=0&&!a[loglen];loglen--);
        i = 0;
        if(loglen<0){
            c[i++] = '0';
        }else for(;loglen>=0;loglen--)
             c[i++] = a[loglen]+'0';
        c[i] = 0;
        strcpy(a,c);
}
char a[500005],b[500005],c[500005],d[500005];
void fexp(int n,int m)
{
    sprintf(a,"%d",1);
    sprintf(b,"%d",n);
    while(m){
        if(m&1)cal(a,b,d);
        cal(b,b,d);
        m >>= 1;
    }
}
int main()
{
    int i,k,j,t;
    for(i = 3; i <= 100000; ++ i){
        k = log10(i) * i + 1;
        as[k] = i;
    }
    scanf("%d",&t);
    while(t--){
        scanf("%s",c);
        k = strlen(c);
        if(k==1){
            if(c[0]=='1')puts("1");
            else if(c[0]=='4')puts("2");
            else puts("-1");
        }
        else if(as.find(k)!=as.end()){
            k = as[k];
            fexp(k,k);
            if(strcmp(a,c)==0)printf("%d\n",k);
            else puts("-1");
        }else puts("-1");
    }
    return 0;
}

 Guess the Number!的另外一种解法:

思路:由于n^n的特殊性,先用快速幂弄出n^n的后9位,然后比较。如果相等,则进行100次大数除法模拟,最后判断。
(实际上,数据很水,上面的都可以不要,只要测试一次大数除法就过了)
View Code
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
#include<string.h>
#include<map>
#define LL long long
using namespace std;
map<int,int>as;
char c[500005];
int cnt;
int fun(int x)
{
    int i,j=0,k=0,t;
    cnt++;
    if(cnt>100)return 1;//控制100次
    for(i = 0; c[i]; ++ i){
        k = k * 10 + c[i] - '0';
        t = k / x;
        while(k>=x)k-=x;
        if(j||t)c[j++]=t+'0';
    }
    c[j]=0;
    return !k;
}
int fexp(LL a,int b,LL mod)
{
    LL ans = 1;
    while(b){
        if(b&1)ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }return (int)ans;
}
int main()
{
    int i,k,j,t;
    char a[100];
    for(i = 3; i <= 100000; ++ i){
        k = log10(i) * i + 1;
        as[k] = i;
    }
    scanf("%d",&t);
    while(t--){
        scanf("%s",c);
        k = strlen(c);
        cnt = 0;
        if(k==1){
            if(c[0]=='1')puts("1");
            else if(c[0]=='4')puts("2");
            else puts("-1");
        }
        else if(as.find(k)!=as.end()){
            k = as[k];
            int d = fexp(k,k,1e9);
            sprintf(a,"%d",d);
            int la = strlen(a)-1;
            int lc = strlen(c)-1;
            while(la>=0){if(a[la]^c[lc])break;la--;lc--;}//比较尾数
            if(la<0){
                j = k;
                while(j--){if(!fun(k))break;}
                if(j<0)printf("%d\n",k);
                else puts("-1");
            }else puts("-1");
        }else puts("-1");
    }
    return 0;
}

 

posted on 2012-08-26 20:51  aigoruan  阅读(242)  评论(0)    收藏  举报

导航