题意: 给出K1,求一个12位数(不含前导0)K2,使得K1^K2 mod (10^12) = K2.
解法: 求不动点问题。
有一个性质: 如果12位数K2满足如上式子的话,那么K2%1,K2%10,K2%100,...,K2%10^12都会满足如上式子。那么我们可以dfs从后往前一个一个找出这个数的每一位。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define SMod 1000000000000 #define ll long long using namespace std; #define N 10007 ll K1,K2; long long mul(long long a,long long b,long long mod) { ll ite = (1LL<<20)-1; return (a*(b>>20)%mod*(1ll<<20)%mod+a*(b&(ite))%mod)%mod; } ll fastm(ll a,ll b,ll m) { ll res = 1LL; while(b) { if(b&1LL) res = mul(res,a,m); a = mul(a,a,m); b >>= 1; } return res; } ll wei[16],ans; bool dfs(int c,ll now) { if(c == 13) { if(now >= wei[12]) { ans = now; return true; } return false; } ll W = wei[c]; for(ll i=0;i<=9;i++) { ll tmp = W*i+now; if(fastm(K1,tmp,W) != tmp%W) continue; if(dfs(c+1,tmp)) return true; } return false; } int main() { int t,cs = 1; wei[0] = 1LL; for(int i=1;i<=13;i++) wei[i] = wei[i-1]*10LL; while(scanf("%lld",&K1)!=EOF && K1) { dfs(0,0); printf("Case %d: Public Key = %lld Private Key = %lld ",cs++,K1,ans%SMod); } return 0; }
还有一种循环迭代的方法,随机选取一个超过10^12的数,如1000000000007,将其代入计算,如果f(x)!=x,那么令x=f(x),如此循环,能在短时间内找出合法解。不知道为啥。。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #define SMod 1000000000000 #define ll long long using namespace std; ll K1,K2; long long mul(long long a,long long b,long long mod) { ll ite = (1LL<<20)-1; return (a*(b>>20)%mod*(1ll<<20)%mod+a*(b&(ite))%mod)%mod; } ll fastm(ll a,ll b,ll m) { ll res = 1LL; while(b) { if(b&1LL) res = mul(res,a,m); a = mul(a,a,m); b >>= 1; } return res; } ll f(ll x) { return fastm(K1,x,SMod); } ll gao(ll x) { while(1) { ll fx = f(x); if(fx == x) return x; x = fx; } } int main() { int t,cs = 1; while(scanf("%lld",&K1)!=EOF && K1) { printf("Case %d: Public Key = %lld Private Key = %lld ",cs++,K1,gao(1000000000007)); } }