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;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!