首先把底数 ((-1)) 消掉:
[(-1)^n=1-2 imes (n\%2)=1-2 imes (n-lfloorfrac n 2
floor imes 2)
]
令 $k=sqrt r $,所以原式等于:
[egin{aligned}
sumlimits_{i=1}^n(-1)^{lfloor ik
floor}&=sumlimits_{i=1}^n (1-2 imes(lfloor ik
floor-lfloor frac{ik}2
floor imes 2 ))\
&=n-2sumlimits_{i=1}^n lfloor ik
floor + 4sumlimits_{i=1}^nlfloor frac{ik}2
floor
end{aligned}
]
发现后两项都是形如 (sumlimits_{i=1}^n lfloor ik floor) 的形式,可以统一做。
如果 (kgeq 1),则可以考虑将 (ilfloor k floor) 提出来,这里不再赘述,只考虑 (k<1) 的情况。
考虑这个式子的几何意义:直线 (y=kx,y=0,x=n) 围成的三角形中的格点个数(不包括 (y=0) 上的点)。
我们把图像沿 (y=x) 翻转(然后取个补集),式子就变成了 (sumlimits_{i=1}^{lfloor kn floor}lfloorfrac 1 k i floor)。
发现 (n) 严格递减,可以证明复杂度是 (log) 级别的。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
LL n,r;
long double Sqr;
LL calc(LL n,LL a,LL b,LL c)
{
if(!n) return 0;
if(n==1) return (LL)((a*Sqr+b)/c);
LL G=__gcd(a,__gcd(b,c));
if(G!=1)
a/=G,b/=G,c/=G;
// printf("%lld %lld %lld %lld
",n,a,b,c);
long double k=(a*Sqr+b)/c;
LL p=LL(k);
if(k>=1.0)
return calc(n,a,b-p*c,c)+(1+n)*n/2*p;
LL q=(LL)(n*k);
return n*q-calc(q,a*c,-b*c,a*a*r-b*b);
}
void init()
{
scanf("%lld %lld",&n,&r);
}
void work()
{
Sqr=sqrt(r);
LL S=(LL)(Sqr);
if(S*S==r)
{
if(S%2==0) printf("%lld
",n);
else printf("%lld
",n%2==1?-1ll:0);
return;
}
LL ans=(n-2*calc(n,1,0,1)+4*calc(n,1,0,2));
printf("%lld
",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
init(),
work();
return 0;
}