专栏文章
AT_abc428_d 题解
AT_abc428_d题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @minkfe2w
- 此快照首次捕获于
- 2025/12/02 03:52 3 个月前
- 此快照最后确认于
- 2025/12/02 03:52 3 个月前
如果你比赛的时候调了半年没调出来,赛后发现是二分的边界设小了,你也会崩溃的,相信我。
观察这个 的定义,发现如果给定的是 且 固定的话, 的位数会直接影响整个的结果。因为,假设 的位数为 ,那么这里的值就是 。很显然,虽然 固定,但是它后面乘的那个 是根据 的具体值在不断变化的。
然后由于 的这个范围也就个 的一个级别,不大,因此可以枚举这个位数 ,这里简单记为 。
考虑在固定了位数 之后,你的这个值的取值范围在一个怎样的趋势。
不难发现 。前面那个 我倒能理解,可这个 是什么东西啊喂?想想吧!如果这里要有 位,至少也要有 次方,这是最小的 位数了,不然根本不可能有 位啊!换句话说,如果 且 的话,像 、 这种是不会算进去的。至于和 取 ,问我 是什么,题目中说了那个数的取值范围,至少为 ,因此在这里至少也是 咯。
求完了, 呢?同样可得出 。 很好理解,就是当前面的前缀不为 了之后肯定就不算了,那么当 且 的时候这个右边界就是 ;但是对 取 又是个什么东西呢?因为题目给定的最大是 ,加上 ,这个算出来的值已经是最大上界了,你不可能比这个还多呀!还多,那也取不到一个 的数字了。
算出 和 之后,就可以开始算了。这边采用的二分,好像也可以开根。算出 这个范围内有多少个完全平方数,加进答案里就行。
最后提一嘴 的枚举范围,很显然,最小是 的位数,最大是 的位数。
具体实现上,我弄了两个函数, 用于算出 的位数,而 则返回 。
CPP#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define fr first
#define se second
#define pb push_back
using namespace std;
LL T,c,d,St,Ed,Ans;
LL read(){
LL su=0,pp=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
return su*pp;
}
LL Lth(LL x){
LL cnt=0;
while(x)cnt++,x/=10;
return cnt;
}
LL Mth(LL h){
LL x=1;
while(h--)x*=10;
return x;
}
LL Fd(LL D){
LL l=1,r=3000000000,res=0;
//这里一定一定一定要开到 3e9 啊!(2e9 疑似也可以,但是不严谨
//我赛时开的 1e9 愣是卡得我 WA *2 呜呜呜呜呜呜
while(l<=r){
LL mid=(l+r)/2;
LL x=mid*mid;
if(x<=D)res=mid,l=mid+1;
else r=mid-1;
}return res;
}
int main(){
T=read();
while(T--){
c=read(),d=read();
St=Lth(c+1),Ed=Lth(d+c),Ans=0;
for(LL i=St;i<=Ed;i++){
LL L=c*Mth(i)+max(c+1,Mth(i-1));
LL R=min((c+1)*Mth(i)-1,c*Mth(i)+c+d);
if(L<=R)Ans+=Fd(R)-Fd(L-1);
}cout<<Ans<<"\n";
}
return 0;
}
如果本篇题解对你有帮助的话,麻烦你点一个小小的赞,真是太感谢啦!
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...