【題解】AT agc057A Antichain of Integer Strings
記 \(f(x)\) 為最小的大于 \(x\) 的 \(y\),使得 \(x\) 是 \(y\) 的子串。易得:
\[f(x)=\min(10x,x+10^{|x|})
\]
其中 \(|x|\) 表示 \(x\) 的位數。
可以發現,\(f(x)\) 為一個嚴格單調遞增的函數。
考慮貪心策略,顯然選小的數不如選大的數優,因為小的數更有可能成為別的數的子串。于是,我們要求的其實就是這樣一個集合 \(\mathbb{A}\),滿足:
\[\mathbb{A}=\{x\in[l,r]\mid f(x)>r\}
\]
因為 \(f(x)\) 是嚴格單增的,因此二分即可。
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define read(x){\
char ch;\
int fu=1;\
while(!isdigit(ch=getchar()))\
fu-=(ch=='-')<<1;\
x=ch&15;\
while(isdigit(ch=getchar()))\
x=(x<<1)+(x<<3)+(ch&15);\
x*=fu;\
}
#define int ll
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int pw10[]={
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000};
il int len(int x){
int res=0;
do{
res++,x/=10;
}while(x);
return res;
}
il int f(int x){
return min(x*10,x+pw10[len(x)]);
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
// for(int i=1;i<=33;i++){
// cout<<i<<" "<<f(i)<<"\n";
// }
int T;
read(T);
while(T--){
int l,r,L,R;
read(l)read(r);
L=l,R=r;
while(l<r){
int mid=(l+r)>>1;
if(f(mid)>R){
r=mid;
}
else{
l=mid+1;
}
}
printf("%d\n",R-l+1);
}
return 0;
}
}
signed main(){return asbt::main();}

浙公網安備 33010602011771號