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\ ...
随机推荐
- 集合(List、Set、Map)
List,Set是继承自Collection接口,Map不是 public interface List<E> extends Collection<E> { public i ...
- streamsets 错误记录处理
我们可以在stage 级别,或者piepline 级别进行error 处理配置 pipeline的错误记录处理 discard(丢踢) send response to Origin pipeline ...
- OPENQUERY用法以及使用需要注意的地方
对给定的链接服务器执行指定的传递查询.该服务器是 OLE DB 数据源.OPENQUERY 可以在查询的 FROM 子句中引用,就好象它是一个表名.OPENQUERY 也可以作为 INSERT.UPD ...
- macOS -- Mac系统如何编辑hosts文件
Hosts是一个没有扩展名的系统文件,其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联"数据库",当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文 ...
- am335x_y蜂鸣器驱动
修改文件:1.板级文件/arch/arm/mach-omap2/board-am335xevm.c static struct platform_device buzzer_device= { .na ...
- LogHelp 日记分天记录,只记30天日记
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Tex ...
- 解决:win8.1 oepnvpn客户端 redirect-gateway def1无效,自动获取的IP没有网关问题
解决:win8.1 oepnvpn客户端 redirect-gateway def1无效,自动获取的IP没有网关问题 该问题是操作系统权限问题,需要将程序设置为以管理员模式运行和以windows7兼容 ...
- 冒泡排序算法-Python实现
#-*- coding: UTF-8 -*- import numpy as np def BubbleSort(a): for i in xrange(0, a.size): for j in xr ...
- Makefile之自动变量篇
自动变量假设您编写一个编译‘.c’文件生成‘.o’文件的规则:您怎样编写命令‘CC’,使它能够操作正确的文件名?您当然不能将文件名直接写进命令中,因为每次使用隐含规则操作的文件名都不一样. 您应该使用 ...
- FastDFS简介和安装
FastDFS是一个轻量级的开源分布式文件系统 FastDFS主要解决了大容量的文件存储和高并发访问的问题,文件存取时实现了负载均衡 FastDFS实现了软件方式的RAID,可以使用廉价的IDE硬盘进 ...