https://ac.nowcoder.com/acm/contest/12606/C

 

题意:在不进位乘法下,给出n,求最小的满足a*a=n的正整数a

 

若n是偶数位则无解,因为若n的每一位编号位0-2*L,如果低位是0号,相乘,结果最低位是0号位,最高位是 2L*2L 号位,这一共是奇数个位

若n有L位,那么a有(L+1)/2位

因为要求最小正整数,所以要从高位到低位dfs

直接枚举a的每一位填什么

类似于列乘法竖式,a的每一位对n中的数位都有一个能产生影响的区间

每填一次就判断当前是否合法:

如果a的当前位不是最低位,就判断从n的最高位 到 a的低一位影响不到的位 是否合法

如果a的当前位是最低位,就判断所有位是否合法

 

#include<cstdio>
#include<cstring>

typedef long long LL;

using namespace std;

int lenn,lena;
int a[60],n[60],b[60];
bool tag;

//int c[10][5]={{1,0},{2,1,9},{0},{0},{2,2,8},{1,5},{2,4,6},{0},{0},{2,3,7}};

void dfs(int p)
{
    int x;
    bool flag;
    if(!p)
    {
        for(int i=0;i<10;++i)
        {
            a[p]=i;
            flag=true;
            for(int j=lenn-1;j>=0 && flag;--j)
            {
                x=0;
                for(int k=0;k<=j;++k) x+=a[k]*a[j-k];
                if(x%10!=n[j]) flag=false;
            }
            if(flag)
            {
                tag=true;
                for(int i=lena-1;i>=0;--i) printf("%d",a[i]);
                return;
            }
        }
        return;
    }
    int i=0;
    if(p==lena-1) i=1;
    for(i=0;i<10;++i)
    {
        a[p]=i;
        flag=true;
        for(int j=lenn-1;j>=p+lena-1 && flag;--j)
        {
            x=0;
            for(int k=0;k<=j;++k) x+=a[k]*a[j-k];
            if(x%10!=n[j]) flag=false;
        }
        if(flag)
        {
            dfs(p-1);
            if(tag) return;
        }
    }
}

int main()
{
    char s[28];
    scanf("%s",s);
    if(s[0]==0)
    {
        printf("0");
        return 0;
    }
    int l=strlen(s);
    for(int i=l-1;i>=0;--i) n[lenn++]=s[i]-'0';
    lena=lenn+1>>1;
    dfs(lena-1);
    if(!tag) printf("-1"); 
}

 

作者:xxy