传说,这是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); } }