其中 d 是 998244353k 的十进制位数。由 \overline s\equiv b\pmod{998244353},我们可以借助逆元计算 {10}^g 的值。如果最小的 g 可以让 s 的长度不大于 114514,那么结束枚举,否则递增 k 继续枚举。关于求 g 的方法,容易想到 BSGS,但是 BSGS 需要一个 \sqrt{998244353}\approx3\times{10}^4 次的循环,并且平均查询次数为 \frac{998244353T}{114514}\approx3\times{10}^5,时间复杂度不能接受。继续想到用哈希表预处理 {10}^g \rightarrow g 的映射,可以实现 \mathcal{O}(1) 的查询,时间复杂度可以接受。
实现中注意一些细节:
如果 a \equiv 0 \pmod{10},令 a \leftarrow a + 998244353;
如果 \mathrm{inv}(a) \equiv 0 \pmod{998244353},令 a \leftarrow a + 998244353;
如果 k \equiv 0 \pmod{10},那么 998244353k 末尾为 0,这次枚举提供的信息极少,可以跳过。
AC 代码
目前是最优解。
#include<bits/stdc++.h>
using namespace std;
const int N=114490,M=998244353;
struct E{//哈希表
int x,i;
};
vector<E> mp[N];
int query(int x){
for(E v:mp[x/(M/N)]){
if(x==v.x)return v.i;
}
return -1;
}
long long T,a,b;
long long inv(long long x){
long long res=0;
for(;x;x/=10)res=res*10+x%10;
return res;
}
int qpow(int a,int b){
int res=1;
for(;b;a=1ll*a*a%M,b>>=1){
if(b&1)res=1ll*res*a%M;
}
return res;
}
void solve(){
cin>>a>>b;
while(a%10==0||inv(a)%M==0)a+=M;
for(long long ia=inv(a),c=M;;c+=M){
if(c%10==0)continue;//剪枝
long long d=ia,e=c,f=0;
for(;e;e/=10)d=d*10%M,f=f*10+e%10;
int g=(b-f)%M*qpow(d,M-2)%M,h=query(g<0?g+M:g);
if(h>=0){
cout<<c<<string(h,'0')<<a<<'\n';
break;
}
}
}
int main(){
cin.tie(0)->sync_with_stdio(0);
for(int i=0,x=1;i<N;x=x*10ll%M)mp[x/(M/N)].push_back({x,i++});//预处理
for(cin>>T>>a;T--;)solve();
}