P14304 【MX-J27-T1】分块
我们发现这个题是 T1,但它的 \(n\) 很大,于是我们可以合理推断这是个结论题或诈骗题。
我们考虑 \([m^2,(m+1)^2)\) 这个区间里有哪些数满足题中所述的条件。显然 \([1^2,2^2),[2^2,3^2), \cdots ,[m^2,(m+1)^2),[(m+1)^2,(m+2)^2), \cdots\) 这些区间拼起来肯定是连续的,不会少算答案。
这样的好处很显然,可以直接去掉根号下取整,也就是对于这个区间里的任意一个数 \(x\),\(\lfloor \sqrt{x} \rfloor = m\)。
这样的话问题就转换成了这个区间里有多少 \(m\) 的因数。那不就是 \(m^2,m^2+m,m^2+2m\) 这三个嘛(因为 \((m+1)^2=m^2+2m+1\),所以 \(m^2+3m,m^2+4m\) 及之后的数并不在这个区间内)。
也就是对于所有形如这样的区间,都只有 3 个数满足条件。
所以我们对于每个 \(n\),找到最大的一个正整数 \(m\) 使得 \(m^2 \le n\),这样最后一个在区间范围内的、形如上述区间的区间就是 \([(m-1)^2,m^2)\),所以前面会有 \(m-1\) 个这样的区间,答案就会先累加一个 \(3(m-1)\)。
接下来对 \(n\) 分类讨论一下,看看对于 \([m^2,(m+1)^2)\) 这个区间,\(m^2,m^2+m,m^2+2m\) 这三个数是否小于 \(n\) 即可,小于则将它们累加进答案。
代码:
P14304
#include<bits/stdc++.h>
#define int __int128
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<48){
if(c=='-') f=-1;
c=getchar();
}
while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x<10) putchar(x+'0');
else write(x/10),putchar(x%10+'0');
}
int q;
inline int erfen(int x){
int l=1,r=x;
while(l<r){
int mid=(l+r+1)>>1;
if(mid*mid<=x){
l=mid;
}
else{
r=mid-1;
}
}
return l;
}
signed main(){
q=read();
while(q--){
int n=read();
int fang=erfen(n);
//为了防止sqrt下取整有误差,我用了一个手写二分
int ans=3*fang-3;
//第一次累加答案,然后分讨
if(n<fang*(fang+1)){//只能取m^2
ans+=1;
}
else if(n<fang*(fang+2)){//能取的是m^2,m^2+m
ans+=2;
}
else{//m^2,m^2+m,m^2+2m三个数都能取
ans+=3;
}
write(ans);printf("\n");
}
return 0;
}
喜欢的话不妨点点赞呀 qwq

浙公网安备 33010602011771号