Luogu 5170 【模板】类欧几里得算法
原理不难但是写起来非常复杂的东西。
我觉得讲得非常好懂的博客。 传送门
我们设
$$f(a, b, c, n) = \sum_{i = 0}^{n}\left \lfloor \frac{ai + b}{c} \right \rfloor$$
$$g(a, b, c, n) = \sum_{i = 0}^{n}i\left \lfloor \frac{ai + b}{c} \right \rfloor$$
$$h(a, b, c, n) = \sum_{i = 0}^{n}\left \lfloor \frac{ai + b}{c} \right \rfloor^2$$
先考虑一个结论
$$\left \lfloor \frac{Ax}{y} \right \rfloor = \left \lfloor \frac{A(x \mod y)}{y} \right \rfloor + A\left \lfloor \frac{x}{y} \right \rfloor$$
那么有
$$\left \lfloor \frac{ai + b}{c} \right \rfloor = \left \lfloor \frac{(a \mod c)i + (b \mod c)}{c} \right \rfloor + i\left \lfloor \frac{a}{c} \right \rfloor + \left \lfloor \frac{b}{c} \right \rfloor$$
这个东西可以把$a \geq c$ 或者$b \geq c$的情况转化成$a,b < c$的情况。
F
先看看这个比较好做的$f$。
注意到当$a \geq c$或者$b \geq c$的时候,我们可以用以上的结论把$a$或者$b$降下来,有
$$f(a, b, c, n) = \left \lfloor \frac{b}{c} \right \rfloor(n + 1) + \left \lfloor \frac{a}{c} \right \rfloor \frac{n(n + 1)}{2} + f(a \mod c, b \mod c, c, n)$$
那么当$a, b < c$的时候,有
$$f(a, b, c, n) = \sum_{i = 0}^{n}\sum_{j = 1}^{m}[\left \lfloor \frac{ai + b}{c} \right \rfloor \geq j]$$
为了方便把$\left \lfloor \frac{an + b}{c} \right \rfloor$记为$m$。
$$f(a, b, c, n) = \sum_{i = 0}^{n}\sum_{j = 0}^{m - 1}[\left \lfloor \frac{ai + b}{c} \right \rfloor \geq j + 1]$$
$$= \sum_{i = 0}^{n}\sum_{j = 0}^{m - 1}[ai \geq cj + c - b]$$
$$= \sum_{i = 0}^{n}\sum_{j = 0}^{m - 1}[ai > cj + c - b - 1]$$
$$= \sum_{i = 0}^{n}\sum_{j = 0}^{m - 1}[i > \left \lfloor \frac{cj + c - b - 1}{a} \right \rfloor]$$
注意到这时候$i$这一项可以直接算了。
$$f(a, b, c, n) = \sum_{j = 0}^{m - 1}(n - \left \lfloor \frac{cj + c - b - 1}{a} \right \rfloor)$$
$$= nm - f(c, c - b - 1, a, m - 1)$$
比较方便。
G
按照套路先做$a \geq c$或者$b \geq c$的情况。
$$g(a, b, c, n) = \left \lfloor \frac{b}{c} \right \rfloor\frac{n(n + 1)}{2} + \left \lfloor \frac{a}{c} \right \rfloor \frac{n(n + 1)(2n + 1)}{6} + g(a \mod c, b \mod c, c, n)$$
然后接着按照上述套路弄$a, b < c$的情况。
$$g(a, b, c, n) = \sum_{j = 0}^{m - 1}\frac{(n - \left \lfloor \frac{cj + c - b - 1}{a} \right \rfloor)(n + 1 + \left \lfloor \frac{cj + c - b - 1}{a} \right \rfloor)}{2}$$
$$= \frac{1}{2}(mn(n + 1) - f(c, c - b - 1, a, m - 1) - h(c, c - b - 1, a, m - 1))$$
还要解决$h$。
H
当$a \geq c$或者$b \geq c$的时候
$$h(a, b, c, n) = (n + 1)\left \lfloor \frac{b}{c} \right \rfloor^2 + \frac{n(n + 1)(2n + 1)}{6}\left \lfloor \frac{a}{c} \right \rfloor^2 + n(n + 1)\left \lfloor \frac{b}{c} \right \rfloor\left \lfloor \frac{a}{c} \right \rfloor + h(a \mod c, b \mod c, c, n) + 2\left \lfloor \frac{a}{c} \right \rfloor g(a \mod c, b \mod c, c, n) + 2\left \lfloor \frac{b}{c} \right \rfloor f(a \mod c, b \mod c, c, n)$$
好麻烦啊……
当$a, b < c$的时候需要一些操作
$$n^2 = 2 \times \frac{n(n + 1)}{2} - n = 2\sum_{i = 1}^{n}i - n$$
可以得到
$$h(a, b, c, n) = \sum_{i = 0}^{n}(2\sum_{j = 1}^{\left \lfloor \frac{ai + b}{c} \right \rfloor}j - \left \lfloor \frac{ai + b}{c} \right \rfloor)$$
$$= 2\sum_{i = 0}^{n}\sum_{j = 1}^{\left \lfloor \frac{ai + b}{c} \right \rfloor}j - f(a, b, c, n)$$
$$= 2\sum_{j = 0}^{m - 1}(j + 1)\sum_{i = 0}^{n}[\left \lfloor \frac{ai + b}{c} \right \rfloor \geq j + 1] - f(a, b, c, n)$$
$$= 2\sum_{j = 0}^{m - 1}(j + 1)(n - \left \lfloor \frac{cj + c - b - 1}{a} \right \rfloor) - f(a, b, c, n)$$
$$= nm(m + 1) - 2g(c, c - b - 1, a, m - 1) - 2f(c, c - b - 1, a, m - 1) - f(a, b, c, n)$$
大概就是这样了。
在计算的时候如果只考虑$(a, c)$这两项的话相当于每一次把$(a, c)$变成了$(c, a \% c)$,所以时间复杂度和欧几里得算法相同,递归层数是$log$层。
时间复杂度$O(Tlogn)$。
因为递归的式子很一致,在计算的时候应当三个东西一起算比较快。
Code:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const ll P = 998244353LL; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void inc(T &x, T y) {
x += y;
if (x >= P) x -= P;
} template <typename T>
inline void sub(T &x, T y) {
x -= y;
if (x < ) x += P;
} inline ll fpow(ll x, ll y) {
ll res = ;
for (; y > ; y >>= ) {
if (y & ) res = res * x % P;
x = x * x % P;
}
return res;
} namespace Likegcd {
struct Node {
ll f, g, h;
}; #define f(now) now.f
#define g(now) now.g
#define h(now) now.h const ll inv2 = fpow(, P - );
const ll inv6 = fpow(, P - ); inline Node solve(ll a, ll b, ll c, ll n) {
Node res;
if (!a) {
f(res) = (b / c) * (n + ) % P;
g(res) = (b / c) * (n + ) % P * n % P * inv2 % P;
h(res) = (b / c) * (b / c) % P * (n + ) % P;
return res;
} f(res) = g(res) = h(res) = ;
if (a >= c || b >= c) {
Node tmp = solve(a % c, b % c, c, n);
inc(f(res), (a / c) * n % P * (n + ) % P * inv2 % P);
inc(f(res), (b / c) * (n + ) % P);
inc(f(res), f(tmp)); inc(g(res), (a / c) * n % P * (n + ) % P * (( * n + ) % P) % P * inv6 % P);
inc(g(res), (b / c) * n % P * (n + ) % P * inv2 % P);
inc(g(res), g(tmp)); inc(h(res), (a / c) * (a / c) % P * n % P * (n + ) % P * (( * n + ) % P) % P * inv6 % P);
inc(h(res), (b / c) * (b / c) % P * (n + ) % P);
inc(h(res), (a / c) * (b / c) % P * n % P * (n + ) % P);
inc(h(res), h(tmp));
inc(h(res), 2LL * (a / c) % P * g(tmp) % P);
inc(h(res), 2LL * (b / c) % P * f(tmp) % P); return res;
} if (a < c && b < c) {
ll m = (a * n + b) / c;
Node tmp = solve(c, c - b - , a, m - ); f(res) = n * m % P;
sub(f(res), f(tmp)); g(res) = n * (n + ) % P * m % P;
sub(g(res), f(tmp));
sub(g(res), h(tmp));
g(res) = g(res) * inv2 % P; h(res) = n * m % P * (m + ) % P;
sub(h(res), 2LL * g(tmp) % P);
sub(h(res), 2LL * f(tmp) % P);
sub(h(res), f(res)); return res;
} return res;
} } int main() {
int testCase;
read(testCase);
for (ll a, b, c, n; testCase--; ) {
read(n), read(a), read(b), read(c);
Likegcd :: Node ans = Likegcd :: solve(a, b, c, n);
printf("%lld %lld %lld\n", ans.f, ans.h, ans.g);
}
return ;
}
Luogu 5170 【模板】类欧几里得算法的更多相关文章
- Solution -「Luogu 5170」类欧几里得算法
推柿子大赛了属于是. 题目要求三个柿子,不妨分别记为: \[\begin {align} f (a, b, c, n) &= \sum \limits _{i = 0} ^{n} \lfloo ...
- [P5170] 类欧几里得算法
"类欧几里得算法"第二题 P5170 [题意]已知\(n,a,b,c\),求 \[ \begin{aligned} f_{1}(a,b,c,n)&=\sum_{i=0}^n ...
- 模板——扩展欧几里得算法(求ax+by=gcd的解)
Bryce1010模板 /**** *扩展欧几里得算法 *返回d=gcd(a,b),和对应等式ax+by=d中的x,y */ long long extend_gcd(long long a,long ...
- LOJ138 类欧几里得算法
类欧几里得算法 给出 \(T\) 组询问,每组用 \(n, a, b, c, k_1, k_2\) 来描述.对于每组询问,请你求出 \[ \sum_{x = 0} ^ {n} x ^ {k_1} {\ ...
- Solution -「LOJ #138」「模板」类欧几里得算法
\(\mathcal{Description}\) Link. \(T\) 组询问,每次给出 \(n,a,b,c,k_1,k_2\),求 \[\sum_{x=0}^nx^{k_1}\left\ ...
- BZOJ3817 Sum(类欧几里得算法)
设$t=\sqrt r$,原题转化为$\sum_{x=1}^n(4*\lfloor\frac{tx}2\rfloor-2*\lfloor tx\rfloor+1)$考虑如何求$\sum_{x=1}^n ...
- 洛谷P5170 【模板】类欧几里得算法(数论)
传送门 此题剧毒,公式恐惧症患者请直接转去代码→_→ 前置芝士 基本数论芝士 题解 本题就是要我们求三个函数的值 \[f(a,b,c,n)=\sum_{i=0}^n \left\lfloor\frac ...
- [BZOJ2987]Earthquake:类欧几里得算法
分析 类欧的式子到底是谁推的啊怎么这么神仙啊orz! 简单说一下这道题,题目中的约束条件可以转化为: \[ y \leq \frac{c-ax}{b} \] 有负数怎么办啊?转化一下: \[ y \l ...
- 【LuoguP4433】[COCI2009-2010#1] ALADIN(含类欧几里得算法推导)
题目链接 题意简述 区间赋值模意义下等差数列,询问区间和 \(N\leq 10^9,Q\leq 10^5\) Sol 每次操作就是把操作区间\([L,R]\)中的数赋值成: \[(X-L+1)*A\ ...
随机推荐
- 浅谈c#垃圾回收机制(GC)
写了一个window服务,循环更新sqlite记录,内存一点点稳步增长.三天后,内存溢出.于是,我从自己的代码入手,查找到底哪儿占用内存释放不掉,最终明确是调用servicestack.ormlite ...
- 7-17 Hashing(25 分)
The task of this problem is simple: insert a sequence of distinct positive integers into a hash tabl ...
- java编程排序之自定义类型的集合,按业务需求排序
自定义引用类型放入集合中,按实际业务需求进行排序的两种思路 第一种思路: (1)自定义实体类实现java.lang.Comparable接口,重写public int compareTo(Object ...
- 由spring的工厂构造bean想到的
被Spring管理的bean可以是直接创建实例,还可以通过工厂模式来进行创建.例如brave的tracing bean定义: <bean id="tracing" class ...
- Qt中Qstring,char,int,QByteArray之间到转换(转)
11.各种数据类型的相互转换char * 与 const char *的转换char *ch1="hello11";const char *ch2="hello22&qu ...
- 【转】纵表、横表互转的SQL
纵表.横表互转的SQL 原文1:http://takkymj.iteye.com/blog/751401 横表就是普通的建表方式,如一个表结构为: 主键.字段1.字段2.字段3... 如果变成纵表 ...
- C语言的第一次实验报告
一.实验题目,设计思路,实现方法 第四次 分支+循环 加强版 (4.2.7 装睡) 设计思路:由题意可知通过最初输入量判断循环次数,根据输出形式可知在每次循环中需重新定义输入量并判断其是否满足题中条件 ...
- mysql-8 alter命令
当我们需要修改数据表名或者修改数据表字段时,就需要用到Mysql alter命令. 查看表结构: -- 以下2个命令是通用的 show columns from test_alter_tbl; des ...
- 折腾一天,获取下列多选框的所有选中值,原生js可直接通过obj.val()来获取,可jq不行,要通过循环取值来获取;
折腾一天,获取下列多选框的所有选中值,原生js可直接通过obj.val()来获取,可jq不行,要通过循环取值来获取;
- webkit内核的浏览器为什么removeAttribute('style')会失效?
做了一些研究,应该算是理清了问题. 首先,我们在这里常说的「属性」(attributes)其实分为两种:内容属性(content attributes)以及 IDL 属性(IDL attributes ...