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

首先把底数 \((-1)\) 消掉:

\[(-1)^n=1-2\times (n\%2)=1-2\times (n-\lfloor\frac n 2\rfloor\times 2) \]

令 $k=\sqrt r $,所以原式等于:

\[\begin{aligned} \sum\limits_{i=1}^n(-1)^{\lfloor ik\rfloor}&=\sum\limits_{i=1}^n (1-2\times(\lfloor ik\rfloor-\lfloor \frac{ik}2\rfloor\times 2 ))\\ &=n-2\sum\limits_{i=1}^n \lfloor ik\rfloor + 4\sum\limits_{i=1}^n\lfloor \frac{ik}2 \rfloor \end{aligned} \]

发现后两项都是形如 \(\sum\limits_{i=1}^n \lfloor ik\rfloor\) 的形式,可以统一做。

如果 \(k\geq 1\),则可以考虑将 \(i\lfloor k\rfloor\) 提出来,这里不再赘述,只考虑 \(k<1\) 的情况。

考虑这个式子的几何意义:直线 \(y=kx,y=0,x=n\) 围成的三角形中的格点个数(不包括 \(y=0\) 上的点)。

我们把图像沿 \(y=x\) 翻转(然后取个补集),式子就变成了 \(\sum\limits_{i=1}^{\lfloor kn\rfloor}\lfloor\frac 1 k i\rfloor\)

发现 \(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",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",n);
		else printf("%lld\n",n%2==1?-1ll:0);
		return;
	}
	LL ans=(n-2*calc(n,1,0,1)+4*calc(n,1,0,2));
	printf("%lld\n",ans);
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
		init(),
		work();
	return 0;
}
posted @ 2020-09-15 06:03  With_penguin  阅读(183)  评论(0编辑  收藏  举报