题面
题意概括
定义数列
对于所有
现希望求出
数据范围:
题解
首先,这道题既然可以达到
那我们来看看
#include<bits/stdc++.h>
using namespace std;
int main()
{
for(int i=1;i<=100;i++)
{
int ans=1;
for(int j=2;j<=i;j++)
{
if(i/j!=i/(j-1)) ans++;
}
cout<<ans<<" ";
}
}
打出来的表是这样的:
相信已经可以看出来规律了。(证明略,请自行查阅关于数列分块相关论述)
用数学语言描述一下,就是对于
当
当
综上,
根据刚才的结论,我们可以得出:
当
解方程
则
则
则
又
当
接下来就简单了。我们枚举每一个
好了,现在万事俱备,但还是有两个点要注意:
1.极限数据(如long long或unsigned long long,使用__int128可以解决
2.由于 sqrt()常数很大,多次调用可能超时,所以我们要尽量不要再循环里面使用( 你猜我考场上怎么挂分的 )。代码中有注释。
#include<bits/stdc++.h>
using namespace std;
inline long long read()//快读函数,可以快速读取(输入)
{
long long s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
return s*w;
}
long long topoint(long long a)
{
long long res=(long long)floor(sqrt(a*4+1))-1;
return res;
}
void write(__int128 x)
{
if(x>9) write(x/10);
putchar(x%10+'0');
}
int t;
int main()
{
//freopen("discrimination.in","r",stdin);
//freopen("discrimination.out","w",stdout);
scanf("%d",&t);
while(t--)
{
long long n,m,r;
__int128 ans=0;
n=read();
m=read();
r=read();
if(!r) r+=m;
long long last=r;
for(long long i=topoint(r);i<=topoint(n)&&last<=n;i++)
{
while((i+2)*(i+2)<=4*last+1) i++;
//若42行改成i=topoint(last);则仍然正确,因为两者是等价的,但会TLE(80pts)
bool flag=(i%2==1);
long long a=(i+2)/2,rl=min(n,flag==1?a*a+a-1:a*a-1);
long long cnt=((rl-last)/m+1);
ans+=cnt*i;
last+=cnt*m;
}
write(ans);
printf("\n");
}
}