1. 程式人生 > >codeforce Hello 2018 913G

codeforce Hello 2018 913G

n) 鏈接 離散對數 ems 比較 lan andro com efi

題目大意:給你一個子串,其在2^k方的十進制表示中出現過(後100位),讓我們求k(k<10^50)

原題鏈接

SOL :

a長度為n
可以嘗試構造一個數b,使得a10^m+b成為其後綴。

x= a10^m+b,則x=2^k(mod 10^(n+m))

我們發現 2^(n+m)|x,且 not(5|x),

我們先枚舉m ,令 X= a10^m+b,y=a10^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; } } }

codeforce Hello 2018 913G