【题解】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();}
posted @ 2025-01-04 11:11  zhangxy__hp  阅读(49)  评论(0)    收藏  举报