AT_abc428_d 题解

· · 题解

如果你比赛的时候调了半年没调出来,赛后发现是二分的边界设小了,你也会崩溃的,相信我。

观察这个 f 的定义,发现如果给定的是 f(x,y)x 固定的话,y 的位数会直接影响整个的结果。因为,假设 y 的位数为 ly,那么这里的值就是 x \times 10^{ly} + y。很显然,虽然 x 固定,但是它后面乘的那个 10^{ly} 是根据 ly 的具体值在不断变化的。

然后由于 c+d 的这个范围也就个 6 \times 10^9 的一个级别,不大,因此可以枚举这个位数 ly,这里简单记为 i

考虑在固定了位数 i 之后,你的这个值的取值范围在一个怎样的趋势。

不难发现 L = c \times 10^i + \max(c+1,10^{i-1})。前面那个 c \times 10^i 我倒能理解,可这个 \max(c+1,10^{i-1}) 是什么东西啊喂?想想吧!如果这里要有 i 位,至少也要有 10^{i-1} 次方,这是最小的 i 位数了,不然根本不可能有 i 位啊!换句话说,如果 c=183i=3 的话,像 183009183047 这种是不会算进去的。至于和 c+1\max,问我 c+1 是什么,题目中说了那个数的取值范围,至少为 1,因此在这里至少也是 c+1 咯。

算出 $L$ 和 $R$ 之后,就可以开始算了。这边采用的二分,好像也可以开根。算出 $[L,R]$ 这个范围内有多少个完全平方数,加进答案里就行。 最后提一嘴 $i$ 的枚举范围,很显然,最小是 $c+1$ 的位数,最大是 $c+d$ 的位数。 具体实现上,我弄了两个函数,$Lth(x)$ 用于算出 $x$ 的位数,而 $Mth(x)$ 则返回 $10^x$。 ```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; } ``` 如果本篇题解对你有帮助的话,麻烦你点一个小小的赞,真是太感谢啦!