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\ ...
随机推荐
- 区间DP的摸索
(poj真的炸了,以下代码可能有误) 按照下面这个做题顺序,对区间DP不再那么迷了 LOJ1422 是 dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k][j])而不是d ...
- bzoj 4177 Mike的农场
bzoj 4177 Mike的农场 思维有些江化了,一上来就想费用流做法,但其实就是个最小割啊. 考虑先将所有的收益拿到,再减去不能拿的以及三元组 \((i,j,k)\) 产生的代价.即,先让 \(a ...
- POJ1651 Multiplication Puzzle【区间DP】
LINK 每次删除一个数,代价是左右两边相邻的数的当前数的积 第一个和最后一个数不能删除 问最后只剩下第一个数的最后一个数的最小代价 思路 很简单的DP 正着考虑没有办法确定两边的数 那么就把每个区间 ...
- L3-011 直捣黄龙 (30 分)
本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营.首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营.当这样的路径不唯一时,要求选择可以沿途解放最多城镇 ...
- java编程之常见的排序算法
java常见的排序算法 第一种:插入排序 直接插入排序 1, 直接插入排序 (1)基本思想:在要排序的一组数中,假设前面(n-1)[n>=2] 个数已经是排 好顺序的,现在要把第n个数插到前面的 ...
- 51nod 算法马拉松4 B递归(YY)
递归 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 函数f(n,m) { 若n=1或m=1返回a[n][m]; 返回f(n-1,m)异或f(n,m-1); } 读入2<= ...
- Python 缓存机制与 functools.lru_cache(zz)
refer to: http://kuanghy.github.io/2016/04/20/python-cache
- c#:Json字符串转成xml对象
没看到.net framework中有这样的功能, 懒得到处找了, 索性花点时间自己写一个 /* * Created by SharpDevelop. * Date: 2013/6/24 * User ...
- eclipse 3.7 中英文自由切换
最近在学习Java的开发,然后又很多的资料是对于的英文环境讲解,有的资料是对应的中文环境讲解,所以很都对不上号,郁闷啊....... 而且开发的时候,每个人都使用习惯也不相同:有的人喜欢英文界面,有的 ...
- mysql having,group by查询去除重复记录
http://m.jb51.net/article/39302.htm 可以这样去理解group by和聚合函数 http://www.cnblogs.com/wuguanglei/p/4229938 ...