题目传送门
My Blog
我们发现这个题是 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<=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^2ans+=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
