[BZOJ3817][Sum][类欧几里得算法 数论]

50 篇文章 0 订阅
4 篇文章 0 订阅
题目大意:

给定 N<=109,R<=104 ,求:

d=1n(1)drd

思路:

不妨设 x=r ,那么

1dx=12(dx%2)=12(dxdx22)=1+4dx2+2dx

所以:

d=1n=n+4d=1ndx22d=1ndx

考虑表达式的一般形式:

i=1nabx+ci=i=1nki

k>=1 时:

=i=1n(bx+ca+bx+cbx+caaa)i=i=1n(bx+cbx+caaa)i+bx+caC2n

k<1 时:

=knnj=1knabxacb2vc2j

  • 发现新的表达式和原表达式形式类似,因此可以递归求解,辗转的过程类似于欧几里得法求 gcd ,因此被称为类欧。

  • 考虑它的几何意义,相当于是求一个斜边为 y=kx 直角三角形内整点的个数,这个过程相当于把三角形不停翻转。

  • 因为 k>=1 k<1 必定是轮流出现,所以这两步可以在一步内完成。

  • 为什么用cin读入会RE???

代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll T, n, m;
double t;
inline  ll gcd(ll a, ll b) {
    if (!b) return a;
    return gcd(b, a % b);
}
inline ll calc(ll n, ll a, ll b, ll c) {
    if (!n) return 0;
    ll g = gcd(gcd(a, b), c); a /= g, b /= g, c /= g;
    ll k = (t * b + c) / a, ret = n * (n + 1) / 2 * k;
    c -= k * a; k = (t * b + c) / a * n;
    ret += n * k;
    ret -= calc(k, b * b * m - c * c, a * b, -a * c);
    return ret;
}
int main(void) {
    //freopen("in.txt", "r", stdin);
    scanf("%lld", &T);
    while (T--) {
        scanf("%lld%lld", &n, &m); t = sqrt(m);
        if ((ll)t == t) printf("%lld\n", (ll)((m & 1) ? ((n & 1) ? -1 : 0) : n));
        else printf("%lld\n", n + (calc(n, 2, 1, 0) << 2) - (calc(n, 1, 1, 0) << 1));
    }
    return 0;
}

完。

By g1n0st

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值