#类欧几里得算法#洛谷 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;
}
posted @ 2026-10-30 03:05  lemondinosaur  阅读(4)  评论(0)    收藏  举报