luogu P4884 【多少个1?】
最近在学数论,于是来写这道bsgs模板题。
- 正文
题意比较明确,要求
最小的n使得\(111...111\)一共n个\(1\),能膜\(m\)为\(k\)。
即为求
\[111...111 \equiv k \ (mod \ m)
\]
中\(111...111\)的位数\(n\)的最小值。
乍看之下没有思路,但是可以发现把这个数乘\(9\)再加\(1\),就是\(10^{n}\)。
由于同余式两边乘或加某数,依然成立。所以把左右乘\(9\)加\(1\),
就变成了求
\[10^{n} \equiv 9k+1 \ (mod \ m)
\]
\(n\)的最小值。
这个式子就可以用bsgs算法来求
不会bsgs可以去OI-wiki看看。
- 注意
在bsgs计算过程中会爆long long,只开long long会WA后面两个点。要用快(龟)速
乘 或 __int128
存数。
\(Code\):
#include <iostream>
#include <cstdio>
#include <cmath>
#include <map>
using namespace std;
#define int __int128
inline int read(){
register int x=0,f=0,ch=getchar();
while('0'>ch||ch>'9')f^=ch=='-',ch=getchar();
while('0'<=ch&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=getchar();
return f?-x:x;
}
inline void print(int x){
if(x<10){
putchar(x+'0');
return ;
}else print(x/10);
putchar(x%10+'0');
}
map<int,int>vis;
inline int qpow(int x,int p,int P){
register int res=1;
for(;p;p>>=1,x=x*x%P)if(p&1)res=res*x%P;
return res%P;
}
int p,n,m,res,ans=1,Ans;
signed main(){
n=read()*9+1,p=read();n%=p;
m=ceil(sqrt((long long)p));
res=qpow(10,m,p)%p;
vis[n%p]=0;
for(register int i=1;i<=m;++i)
vis[qpow(10,i,p)*n%p]=i;
for(register int i=1;i<=m;++i){
ans=ans*res%p;
if(vis[ans]){
Ans=i*m%p-vis[ans];
print((Ans%p+p)%p);
return 0;
}
}
return 0;
}