UOJ #42. 【清华集训2014】Sum

首先把底数 ((-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;
}
原文地址:https://www.cnblogs.com/With-penguin/p/13670876.html