题解:AT_abc423_g [ABC423G] Small Multiple 2
题目大意
给你一个整数
需要你求出最小的整数
解法
由于笔者过于蒟蒻,所以只能给出一个码量较小的算法。
我们设
那么考虑在
那么组成的整数满足
显然
所以答案
那么我们设在
我们设放在
那么要使
于是我们设
原式等于
由于
由于
即
所以
由于
由于上式的值只有可能是
二分查找
由于
取
::::info[Code]
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int k,cnt,n,len;
int as[N],ans[N],orz,ozr,bz[N];
string s;
void cmp(int len2){
if(len2>len) return;
if(len2<len){
len=len2;
for(int i=0;i<=len;i++) ans[i]=bz[i];
return ;
}
for(int i=len;i>=0;i--){
if(ans[i]<bz[i]) break;
if(ans[i]>bz[i]){
for(int i=0;i<=len;i++) ans[i]=bz[i];
return ;
}
}
}
int f(int n,int a,int b,int c){
if(n==-1) return 0;
if(a==0) return (n+1)*(b/c);
if(a>=c||b>=c) return (n+1)*n/2*(a/c)+(n+1)*(b/c)+f(n,a%c,b%c,c);
int now=f((n*a+b)/c-1,c,c-1-b,a);
return ((n*a+b)/c)*n-now;
}
bool chk(int len,int a,int b,int pw){
int sum=f(len,a,b,k)-f(len,a,b-pw,k);
if(sum>=1) return 1;
else return 0;
}
void calc(int y,int c){
int pw=pow(10,y);
int a=(k-ozr*pw%k)%k;
int b=(k-orz*pw%k)%k;
int l=0,r=pow(10,c)-1,ans=0;
while(l<=r){
int mid=l+r>>1;
if(chk(mid,a,b+k,pw)) ans=mid,r=mid-1;
else l=mid+1;
}
int ct=-1,d=(a*ans+b)%k;
if(d>=pw) return;
while(d) bz[++ct]=d%10,d/=10;
while(ct+1<y) bz[++ct]=0;
for(int i=n;i>=1;i--) bz[++ct]=as[i];
while(ans) bz[++ct]=ans%10,ans/=10;
cmp(ct);
}
void solve(){
cin>>k>>s;
n=s.size();
orz=0,ozr=1;
for(int i=0;i<n;i++) as[i+1]=s[i]-'0';
for(int i=1;i<=n;i++) orz=(orz*10%k+as[i])%k,ozr=ozr*10%k;
int x=k;cnt=0,len=1e7;
while(x) cnt++,x/=10;
for(int i=0;i<=cnt;i++) calc(i,cnt-i);
for(int i=len;i>=0;i--) cout<<ans[i];
cout<<"\n";
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int _;
cin>>_;
while(_--) solve();
return 0;
}
::::