题目大意:给你一个子串,其在2^k方的十进制表示中出现过(后100位),让我们求k(k<10^50)
SOL :
设a长度为n。
可以尝试构造一个数b,使得a⋅10^m+b成为其后缀。
令 x= a⋅10^m+b,则x=2^k(mod 10^(n+m))
我们发现 2^(n+m)|x,且 not(5|x),
我们先枚举m ,令 X= a⋅10^m+b,y=a⋅10^m,我们发现y不总是满足上述性质,那么我们就对b做出约束:
如果 NOT(2^(N+M)|y) X=y+(2^(N+M)-y%2^(N+M)),
如果 5|X ,我们令 X=y+2^(M+N)
那么我们便把X构造出来了,那么我们就只有一个问题了,那就是怎么求K?
2^K=X(mod 10^(n+m)),同除上2^(N+M),那么我们得到:
2^(K-M-N)=X/(2^(N+M))(mod 5^(N+M))
这个柿子,我们对其取对数,简记R=X/(2^(N+M)) 得到:
K-M-N=log2 R(mod 5^(N+M))(这一步牵扯到2个知识点:原根 和 离散对数 )//先挂着dalao的博客吧,以后有空会补的。
那么我们的问题就是求log2 R
我们知道2 是 5 的原根,那么2 也是 5^i 的原根。(不失一般性,我们有 p 是姬(奇)质数,q为其原根,那么q也是 p^l 的原根。l是正整数 )。
由于数量比较大,传统的baby_step_giant_step算法 过不了,怎么破?(传统算法点这里)
那么我们有一个比较厉害的柿子:
设dy,i为模pi意义下的log(g)y,存在 j 满足 di+1=di+j*φ(pi),j∈[0,p)。
#include<bits/stdc++.h> #define LL long long using namespace std; int len(LL x){int a=0; for (;x;a++,x/=10); return a;} LL mul(LL x,LL y,LL mo){ LL anw=0; for (;y>0;y>>=1,x=(x<<1)%mo) if (y&1) (anw+=x)%=mo; return anw; } LL qsm(LL x,LL y,LL mo){ LL anw=1; for (;y>0;y>>=1,x=mul(x,x,mo)) if (y&1) anw=mul(anw,x,mo); return anw; } #define sight(c) (‘0‘<=c&&c<=‘9‘) inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } inline void read(LL &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(LL x){if (x<10) {putchar(‘0‘+x); return;} write(x/10); putchar(‘0‘+x%10);} inline void writeln(LL x){ if (x<0) putchar(‘-‘),x*=-1; write(x); putchar(‘\n‘); } LL n,l,x,T,tp,mo,y,t,k,p5; int main () { read(T); while (T--) { read(k); n=len(k); tp=1; for (int m=0;;m++) { x=k; mo=1ll<<(n+m); if (x%mo) x+=mo-x%mo; if (!(x%5))x+=mo; if ((!(x%mo))&&x%5&&x-k<tp){ y=x>>(n+m); t=0; p5=5; if (y%5==1) t=0; if (y%5==2) t=1; if (y%5==3) t=3; if (y%5==4) t=2; for (int i=1;i<n+m;i++){ while (qsm(2,t,p5*5)!=y%(p5*5)) t+=p5/5*4; p5*=5; } writeln(t+n+m); break; } k*=10,tp*=10; } } }