hdu 4394 Digital Square 记忆化搜索

传说,这是dfs,其实就是暴搜 + 不暴搜的剪枝。

         如我们的n == 21; 那么,我们从个位数1开始搜, 1 * 1 == 1, 9 * 9 == 81,他们的个位数都是1,那么,1和9可以作为我们找的那个数的个位数。 

然后我们就记忆一下这个我们找到的东西,放在ans里面。 

        下面我们开始搜第二位,设搜的是ab的a(其中,我们的b是已经记忆下来的个位)。

        ab * ab % 100 = 21; 那么,我们的2 是不是就由(b * b / 10 + a * b * 2) % 10 得到的。于是,我们就for一遍去找a,找到a了,我们就以同样的方法去找c(如果有c的话)。这样,就是剪枝了。

        最后,如果我们找的n有x位,那么,我们要找的m * m % ? == n 的m最多也只有x位。至此,就结束了。

解题过程:

       WA了一次,因为觉得没必要用__int64的。哎,现在还是觉得没必要,但是就是改成__int64就过了。。。

#include <cstdio>
using namespace std;
__int64 t,digit[20],total,n,ans,remainder,final;
inline __int64 min(__int64 a, __int64 b) {return a > b? b : a;}
void getdigit(__int64 tmp){//得到total = n的位数,digit[]存每个位上分别是什么。
    total = 0;
    while(tmp){
        digit[ ++total] = tmp % 10;
        tmp /= 10;
    }
}
void solve(__int64 pos, __int64 weight, __int64 ans){
    if(total < pos){
        final = min(final,ans); return ;//哎,跟线段树一样,又忘记return了。。。
    }
    for(__int64 k = 0; k < 10; k ++){
        if( (ans * ans / weight + remainder * k % 10) % 10 == digit[pos])
            solve(pos + 1, weight * 10, k * weight + ans);
    }
}
int main(){
    scanf("%I64d",&t);
    while(t --){
        scanf("%I64d",&n);
        getdigit(n);
        final = 2000000000;
        for(__int64 i = 0; i < 10; ++i){
            if(i * i % 10 == digit[1]){
                remainder = i << 1;
                solve(2,10,i);
            }
        }
        if(final == 2000000000)
            puts("None");
        else
            printf("%d\n",final);
    }
}


你可能感兴趣的:(hdu 4394 Digital Square 记忆化搜索)