#类欧几里得算法#洛谷 5172 [清华集训 2014] Sum
分析
当 \(\sqrt{r}\) 为整数时根据其奇偶性和 \(n\) 的奇偶性特判,
否则将幂次变成 \(\sum_{d=1}^n(1-2(\lfloor d\sqrt{r}\rfloor\bmod 2))=n-2\sum_{d=1}^n\lfloor d\sqrt{r}\rfloor+4\sum_{d=1}^n\lfloor \frac{d\sqrt{r}}{2}\rfloor\)
转换成了 \(calc(a,b,c,n)=\sum_{i=1}^n\lfloor\frac{a\sqrt{r}+b}{c}i\rfloor\) 的子问题
按 \(m=\lfloor\frac{a\sqrt{r}+b}{c}\rfloor\) 分类讨论,如果它大于 \(0\),那么就把整数部分剔出来,也就是 \(\frac{mn(n+1)}{2}+calc(a,b-mc,c,n)\)
否则令 \(m=\lfloor n\frac{a\sqrt{r}+b}{c}\rfloor\),交换和式之后将 \(\frac{c}{a\sqrt{r}+b}=\frac{ac\sqrt{r}-bc}{a^2r-b^2}\) 分母有理化,
产生了新的 \(a,b,c\),也就是 \(calc(a,b,c,n)=nm-calc(ac,-bc,a^2r-b^2,m)\),为了防止整数溢出每次都要将 \(a,b,c\) 约分。
代码
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long lll;
lll T,n,r; double sq;
lll calc(lll a,lll b,lll c,int n){
if (!n) return 0;
lll GCD=__gcd(a,__gcd(b,c));
a/=GCD,b/=GCD,c/=GCD;
lll m=(a*sq+b)/c;
if (m) return n*(n+1)/2*m+calc(a,b-c*m,c,n);
else{
m=n*(a*sq+b)/c;
return n*m-calc(a*c,-b*c,a*a*r-b*b,m);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
for (cin>>T;T;--T){
cin>>n>>r,sq=sqrtl(r);
if ((int)sq*(int)sq==r){
if (r&1) cout<<((n&1)?-1:0)<<'\n';
else cout<<n<<'\n';
continue;
}else cout<<n-2*calc(1,0,1,n)+4*calc(1,0,2,n)<<'\n';
}
return 0;
}

浙公网安备 33010602011771号