模板 - 类欧几里得算法

用来快速求解 $\sum\limits_{i=0}^{n}\lfloor \frac{ai+b}{c} \rfloor,\sum\limits_{i=0}^{n}{\lfloor \frac{ai+b}{c} \rfloor}^2,\sum\limits_{i=0}^{n}i\lfloor \frac{ai+b}{c} \rfloor $

有多快呢?据说是log的?反正abc取1e9可以200ms过1e5组询问……

#include <bits/stdc++.h>

typedef long long ll;
constexpr int mod = 998244353;
constexpr ll inv2 = 499122177;
constexpr ll inv6 = 166374059;

ll f(ll a, ll b, ll c, ll n);
ll g(ll a, ll b, ll c, ll n);
ll h(ll a, ll b, ll c, ll n);

struct Query {
    ll f, g, h;
};

Query solve(ll a, ll b, ll c, ll n) {
    Query ans, tmp;
    if(a == 0) {
        ans.f = (n + 1) * (b / c) % mod;
        ans.g = (b / c) * n % mod * (n + 1) % mod * inv2 % mod;
        ans.h = (n + 1) * (b / c) % mod * (b / c) % mod;
        return ans;
    }
    if(a >= c || b >= c) {
        tmp = solve(a % c, b % c, c, n);
        ans.f = (tmp.f + (a / c) * n % mod * (n + 1) % mod * inv2 % mod + (b / c) * (n + 1) % mod) % mod;
        ans.g = (tmp.g + (a / c) * n % mod * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod + (b / c) * n % mod * (n + 1) % mod * inv2 % mod) % mod;
        ans.h = ((a / c) * (a / c) % mod * n % mod * (n + 1) % mod * (2 * n + 1) % mod * inv6 % mod +
                 (b / c) * (b / c) % mod * (n + 1) % mod + (a / c) * (b / c) % mod * n % mod * (n + 1) % mod +
                 tmp.h + 2 * (a / c) % mod * tmp.g % mod + 2 * (b / c) % mod * tmp.f % mod) % mod;
        return ans;
    }
    ll m = (a * n + b) / c;
    tmp = solve(c, c - b - 1, a, m - 1);
    ans.f = (n * (m % mod) % mod - tmp.f) % mod;
    ans.g = (n * (n + 1) % mod * (m % mod) % mod - tmp.f - tmp.h) % mod * inv2 % mod;
    ans.h = (n * (m % mod) % mod * ((m + 1) % mod) % mod - 2 * tmp.g - 2 * tmp.f - ans.f) % mod;
    return ans;
}

inline char nc() {
    static char buf[1000000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}

inline ll read() {
    ll res = 0;
    char ch;
    do
        ch = nc();
    while(ch < 48 || ch > 57);
    do
        res = res * 10 + ch - 48, ch = nc();
    while(ch >= 48 && ch <= 57);
    return res;
}

int main() {
    ll t = read();
    ll n, a, b, c;
    while(t--) {
        n = read(), a = read(), b = read(), c = read();
        Query ans = solve(a, b, c, n);
        printf("%lld %lld %lld\n", (ans.f + mod) % mod, (ans.h + mod) % mod, (ans.g + mod) % mod);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Yinku/p/10776831.html

时间: 2024-10-12 15:56:13

模板 - 类欧几里得算法的相关文章

bzoj3817 Sum 类欧几里得算法

这道题目solution写了两种做法,都讲一下吧. 首先,令x=r^0.5,显然,如果x>2,则可以不断减2到小于二:如果x>1,那么变为2-x.因此此时必有x<1.(特判r为完全平方数的情况).那么令y=1/x,则: 题目等价于在数轴从0~n,以y长度为一个区间(左闭右开)黑白交替染色,求黑色部分覆盖的整点减去白色部分覆盖的整点.然后把最后面零散的部分暴力计算,如果最后一个是黑色的也暴力计算.那么这个时候黑白段数相等,且每一段黑(白)都至少覆盖[y]个点恰好各自抵消[y],那么将每一段

[P5170] 类欧几里得算法

のすたの"类欧几里得算法"第二题 P5170 [题意]已知\(n,a,b,c\),求 \[ \begin{aligned} f_{1}(a,b,c,n)&=\sum_{i=0}^n\lfloor\dfrac{ai+b}{c}\rfloor\f_{2}(a,b,c,n)&=\sum_{i=0}^n\lfloor\dfrac{ai+b}{c}\rfloor^2\f_{3}(a,b,c,n)&=\sum_{i=0}^n\lfloor\dfrac{ai+b}{c}\rf

BZOJ3817 Sum(类欧几里得算法)

设$t=\sqrt r$,原题转化为$\sum_{x=1}^n(4*\lfloor\frac{tx}2\rfloor-2*\lfloor tx\rfloor)$考虑如何求$\sum_{x=1}^n\lfloor\frac{bt+c}ax\rfloor$开始我写了一个真欧几里得来求直线下整点数目,然后由于里头含小数所以不对.于是学习了一下新姿势,思想其实差不多.先把a,b,c同时除以gcd(a,b,c),防止爆int.之后把斜率变成$\frac{bt+c}a-\lfloor\frac{bt+c}a

类欧几里得算法浅谈(部分)

学习类欧几里得算法,因为是蒟蒻,感觉网上很多都看不懂,所以自己写一篇快活快活 第一类求和式: \(F(a,b,c,n)=\sum_{i=0}^n\lfloor\frac{a*i+b}{c}\rfloor\) 对于这样形式的求和,我们有以下的推导: 1.当\(a>=c\)并且\(b>=c\)时,我们有: 对于\(\lfloor\frac{a}{c}\rfloor\), 它实际等价于\(\lfloor\frac{a\mod c}{c}\rfloor+\lfloor\frac{a}{c}\rfloo

类欧几里得算法

对于求和式 $f(a,b,c,n)=\sum_{i=0}^n \lfloor \frac{ai+b}{c} \rfloor$ 当 $a \geq c$ 或 $b \geq c$ 时,设 $a'=a \; mod \; c$,$b'=b \; mod \; c$,有 $$\begin{align*} f(a,b,c,n) = & \sum_{i=0}^n \; \lfloor \frac{ai+b}{c} \rfloor \\ = & \sum_{i=0}^n \; \lfloor \fra

数论,类欧几里得算法

类欧几里得部分转载自不来也不去的一只失忆蝴蝶.%%%

[补档计划] 类欧几里得算法

$$\begin{aligned} f(a, b, c, n) & = \sum_{i = 0}^n \lfloor \frac{ai + b}{c} \rfloor \\ & = \sum_{i = 0}^n \sum_{j = 0}^{m-1} [j < \lfloor \frac{ai + b}{c} \rfloor] \\ & = \sum_{i = 0}^n \sum_{j = 0}^{m-1} [j + 1 \le \lfloor \frac{ai + b}{c}

模板——扩展欧几里得算法

//gcd LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a%b); } //exgcd LL exgcd(LL a, LL b, LL &d, LL &x, LL &y) { if(!b) {d = a; x = 1; y = 0;} else {gcd(b, a%b, d, y, x); y -= x*(a/b);} }

【LuoguP4433】[COCI2009-2010#1] ALADIN(含类欧几里得算法推导)

题目链接 题意简述 区间赋值模意义下等差数列,询问区间和 \(N\leq 10^9,Q\leq 10^5\) Sol 每次操作就是把操作区间\([L,R]\)中的数赋值成: \[(X-L+1)*A\ mod\ B\] 考虑用线段树维护. 我们只需要能快速知道一段区间\([l,r]\)被覆盖后的和就行了,因为覆盖的标记易于下传: \[\sum_{i=l}^{r} (i-L+1)*A\ mod\ B\] 根据基础的数学知识,mod显然不好算,把它拆开: \[\sum_{i=l}^r (i-L+1)*