Solution -「校内题」矩阵求和
Description
共 \(T\) 组数据。对于每组数据,给定 \(a, b, n\),求 \(\sum_{i = 1}^{n} \sum_{j = 1}^{n} \gcd(a^i - b^i, a^j - b^j)\),并取一个让人迷惑的模数 \(10^9 + 9\)。
题目保证 \(\gcd(a, b) = 1\) 且 \(1 \leq T \leq 10, 1 \leq n \leq 10^7, 1 \leq a < b \leq 10^9\)。
Solution
因为笔者太蒻赛时并没有 A 掉此题,故先感谢 lihan 巨巨在赛后讨论中对于时间复杂度优化上(引入整除分块)给我的启发。 /fad
以下为正题,所有未知量均处于正整数域。
Trick 1
试证明:\(\gcd(a^i - b^i, a^j - b^j) = a^{\gcd(i, j)} - b^{\gcd(i, j)}\),其中 \(\gcd(a, b) = 1, a > b\)。
首先明确一条显然的引理 \(1\):若 \(a^i = b^i\),则一定有 \((a^i)^k = (b^i)^k\)。
以及另一条由因式定理可证的显然的引理 \(2\):\(a^i - b^i\) 一定有一个因式为 \(a - b\)。
引理 \(2\) 成立本质上是因为 \(a = b\) 是 方程 \(a^i - b^i = 0\) 的一个通解。故可结合引理 \(1\) 可推广为 \(a^p = b^p\) 是方程 \(a^q - b^q = 0\) 的一个通解,其中 \(p\) 是 \(q\) 的因数。
故可得 \(a^i - b^i\) 一定有一个因式为 \(a^{q_1} - b^{q_1}\),其中 \(q_1\) 是 \(i\) 的因数,同理 \(a^j - b^j\) 一定有一个因式为 \(a^{q_2} - b^{q_2}\),其中 \(q_2\) 是 \(j\) 的因数。
则 \(a^{\gcd(i, j)} - b^{\gcd(i, j)} \mid \gcd(a^i - b^i, a^j - b^j)\)。
接下来尝试证明:\(\gcd(a^i - b^i, a^j - b^j) \mid a^{\gcd(i, j)} - b^{\gcd(i, j)}\)。
引入引理 \(3\):设 \(c = \gcd(a^i - b^i, a^j - b^j)\),则 \(\gcd(c, b) = 1\)。
对于引理 \(3\),若 \(\gcd(c, b) \neq 1\),则有质数 \(p \mid \gcd(c, b)\),故有 \(p \mid \gcd(c, b) \mid b, p \mid \gcd(c, b) \mid c \mid (a^i - b^i)\)。
可得 \(p \mid a^i\),即 \(p \mid a\),所以 \(p \mid \gcd(a, b)\)。此与 \(\gcd(a, b) = 1\) 矛盾,故引理 \(3\) 成立。
记 \(d = \gcd(i, j)\),则由裴蜀定理可得,存在 \(x, y\),使得 \(x \times i - y \times j = \gcd(i, j) = d\)。
又因为 \(c \mid (a^j - b^j)\)。故可由引理 \(2\) 得 \(c \mid (a^{j \times y} - b^{j \times y})\)。所以 \(c \mid a^d \times (a^{j \times y} - b^{j \times y}) = (a^{x \times i} - a^{d} \times b^{j \times y})\)。
又由 \(c \mid (a^i - b^i)\),可知 \(c \mid (a^{x \times i} - b^{x \times i})\),所以有 \(c \mid (a^{d} \times b^{j \times y} - b^{x \times i}) = b^{j \times y} \times (a^{d} - b^{d})\)。
而 \(\gcd(b, c) = 1\),故有 \(c \mid (a^{d} - b^{d})\),即 \(\gcd(a^i - b^i, a^j - b^j) \mid a^{\gcd(i, j)} - b^{\gcd(i, j)}\)。
又因为 \(a^{\gcd(i, j)} - b^{\gcd(i, j)} \mid \gcd(a^i - b^i, a^j - b^j)\)。
故有 \(\gcd(a^i - b^i, a^j - b^j) = a^{\gcd(i, j)} - b^{\gcd(i, j)}\),得证。
Trick 2
试证明:若 \(f(x) = \sum_{i = 1}^{n} \sum_{j = 1}^{n} [\gcd(i, j) = x]\) ,则有 \(f(x) = 2 \times \left( \sum_{i = 1}^{\lfloor \frac {n}{x} \rfloor} \varphi(i) \right) - 1\)。
首先明确一条引理:对于任意 \(i, j\),若 \(\gcd(i, j) = 1\),则有 \(\gcd(i \times x, j \times x) = x\)。
于是我们考虑统计给定范围内有哪些组 \(i, j\) 满足要求。
对于 \(i\),满足条件的 \((i, j)\) 有 \(\varphi(i)\) 组,其中 \(1 < i \leq \lfloor \frac {n} {x} \rfloor, i > j\)。
且不难发现 \((i, j)\) 与 \((j, i)\) 需要分开计算贡献,即 \(2 \times \left( \sum_{i = 2}^{\lfloor \frac {n}{x} \rfloor} \varphi(i) \right)\)。
最后特殊考虑 \(i = 1\) 的情况,仅有 \((1, 1)\) 符合条件,故 \(f(x) = 2 \times \left( \sum_{i = 2}^{\lfloor \frac {n}{x} \rfloor} \varphi(i) \right) + 1\)。
因为我们规定 \(\varphi(1) = 1\),故也有 \(f(x) = 2 \times \left( \sum_{i = 1}^{\lfloor \frac {n}{x} \rfloor} \varphi(i) \right) - 1\)。得证。
Trick 3
根据前两个 Trick 可得:
\]
但分析发现此题并不能使用 \(O(T \times n \log(n))\) 的做法 A 掉。
观察答案式子发现 \(\lfloor \frac {n}{x} \rfloor\) 的形式,故使用整除分块。
对于 \(l, r\),有 \(\lfloor \frac {n}{l} \rfloor = \lfloor \frac {n}{r} \rfloor,\lfloor \frac {n}{l} \rfloor < \lfloor \frac {n}{r + 1} \rfloor\)。则可知其对答案的贡献为:
\]
记 \(p = 2 \times \left( \sum_{i = 1}^{\lfloor \frac {n}{l} \rfloor} \varphi(i) \right) - 1\),再套用等比数列求和公式,故上式可化为:\(\frac {a^{r + 1} - a^l} {a - 1} \times p - \frac {b^{r + 1} - b^l} {b - 1} \times p\)。
然后其他的就没有什么难点了,线性筛求一个 \(\varphi\) 的前缀和,快速幂求答案与逆元,然后跑整除分块即可。
Code
#include <cstdio>
typedef long long LL;
LL Max(LL x, LL y) { return x > y ? x : y; }
LL Min(LL x, LL y) { return x < y ? x : y; }
LL Abs(LL x) { return x < 0 ? -x : x; }
int read() {
int k = 1, x = 0;
char s = getchar();
while (s < '0' || s > '9') {
if (s == '-')
k = -1;
s = getchar();
}
while (s >= '0' && s <= '9') {
x = (x << 3) + (x << 1) + s - '0';
s = getchar();
}
return x * k;
}
LL read_LL() {
int k = 1;
LL x = 0;
char s = getchar();
while (s < '0' || s > '9') {
if (s == '-')
k = -1;
s = getchar();
}
while (s >= '0' && s <= '9') {
x = (x << 3) + (x << 1) + s - '0';
s = getchar();
}
return x * k;
}
void write(LL x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void print(LL x, char s) {
write(x);
putchar(s);
}
const int mod = 1e9 + 9;
const int MAXN = 1e7 + 5;
const int MAXM = 664579 + 5;
LL Quick_Pow(LL a, LL b) {
LL res = 1;
while (b) {
if (b & 1)
res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
bool flag[MAXN];
LL phi[MAXN], sum[MAXN];
int num[MAXM], len = 0;
void Euler(int n) {
flag[1] = true;
phi[1] = 1;
for (int i = 2; i <= n; i++) {
if (!flag[i]) {
num[++len] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= len; j++) {
if (i * num[j] > n)
break;
flag[i * num[j]] = true;
if (i % num[j] == 0) {
phi[i * num[j]] = phi[i] * num[j] % mod;
break;
} else
phi[i * num[j]] = phi[i] * phi[num[j]] % mod;
}
}
sum[1] = 1;
for (int i = 2; i <= n; i++) sum[i] = (sum[i - 1] + phi[i]) % mod;
return;
}
LL calc(int l, int r, int x) { return (Quick_Pow(x, r + 1) - Quick_Pow(x, l) + mod) % mod; }
int main() {
Euler(MAXN - 5);
int t = read();
while (t--) {
LL a = read_LL(), b = read_LL(), ans = 0;
LL inva = Quick_Pow(a - 1, mod - 2) % mod, invb = Quick_Pow(b - 1, mod - 2) % mod;
int n = read(), l, r;
for (l = 1; l <= n; l = r + 1) {
r = n / (n / l);
LL x = ((sum[n / l] << 1) % mod - 1 + mod) % mod;
ans = (ans + calc(l, r, a) * inva % mod * x % mod) % mod;
ans = (ans - calc(l, r, b) * invb % mod * x % mod + mod) % mod;
}
print(ans, '\n');
}
return 0;
}
Solution -「校内题」矩阵求和的更多相关文章
- Solution -「校内题」Xorequ
0x00 前置芝士 数位dp考试里出现的小神题?? 显然考场会选择打表找规律. 数位dp + 矩阵快速幂 0x01 题目描述 给定正整数 \(n\),现有如下方程 \(x \bigoplus 3x = ...
- Solution -「ARC 104E」Random LIS
\(\mathcal{Description}\) Link. 给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...
- Solution -「ARC 101D」「AT4353」Robots and Exits
\(\mathcal{Description}\) Link. 有 \(n\) 个小球,坐标为 \(x_{1..n}\):还有 \(m\) 个洞,坐标为 \(y_{1..m}\),保证上述坐标 ...
- Solution -「国家集训队」「洛谷 P2619」Tree I
\(\mathcal{Description}\) Link. 给一个 \(n\) 个点 \(m\) 条边的带权无向图,边有权值和黑白颜色,求恰选出 \(K\) 条白边构成的最小生成树. ...
- Solution -「ARC 104C」Fair Elevator
\(\mathcal{Description}\) Link. 数轴从 \(1\sim 2n\) 的整点上有 \(n\) 个闭区间.你只知道每个区间的部分信息(可能不知道左或右端点,或者都不知 ...
- Solution -「基环树」做题记录
写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...
- Solution -「CF 1342E」Placing Rooks
\(\mathcal{Description}\) Link. 在一个 \(n\times n\) 的国际象棋棋盘上摆 \(n\) 个车,求满足: 所有格子都可以被攻击到. 恰好存在 \(k\ ...
- 「刷题」THUPC泛做
刷了一下,写一下. T1. 天天爱射击 可以这样想. 我们二分一下每一块木板在什么时刻被击碎. 然后直接用主席树维护的话是\(O(nlog^2n)\)的. 会\(T\),而且是一分不给那种... 那么 ...
- Solution -「CTS 2019」「洛谷 P5404」氪金手游
\(\mathcal{Description}\) Link. 有 \(n\) 张卡牌,第 \(i\) 张的权值 \(w_i\in\{1,2,3\}\),且取值为 \(k\) 的概率正比于 \ ...
随机推荐
- TCP 协议灵魂 12 问,巩固你的网路底层基础!
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 先亮出这篇文章的思维导图 TCP 作为传输层的协议,是一 ...
- k8s入门之Secret(十)
Secret与ConfigMap都是用来存储配置信息的,不同之处在于ConfigMap是明文存储的,而Secret用来保存敏感信息,如:密码.OAuth令牌,ssh key等等.Secret常用有三种 ...
- 结合 Vuex 和 Pinia 做一个适合自己的状态管理 nf-state
一开始学习了一下 Vuex,感觉比较冗余,就自己做了一个轻量级的状态管理. 后来又学习了 Pinia,于是参考 Pinia 改进了一下自己的状态管理. 结合 Vuex 和 Pinia, 保留需要的功能 ...
- Java 15 新特性:隐藏类
什么是隐藏类 隐藏类,是一种不能被其他类直接使用的类.引入隐藏类的主要目的是给框架来使用,使得框架可以在运行时生成类,并通过反射间接使用它们.可能有点抽象,不要紧,下面我们通过一个例子来直观的认识它! ...
- 运维:ITIL V3
TIL 简史 在20 世纪80 年代末期,英国商务部(OGC,Office Government Commerce)发布了ITIL .OGC 最初的目标是通过应用IT 来提升政府业务的效率:目标是能够 ...
- 关于position的relative和absolute分别是相对于谁进行定位的
position:absolute; 他的意思是绝对定位,他是参照浏览器的左上角,配合TOP.RIGHT.BOTTOM.LEFT(下面简称TRBL)进行定位,在没有设定TRBL,默认依据父级的做标原始 ...
- 为什么Java有了synchronized之后还造了Lock锁这个轮子?
众所周知,synchronized和Lock锁是java并发变成中两大利器,可以用来解决线程安全的问题.但是为什么Java有了synchronized之后还是提供了Lock接口这个api,难道仅仅只是 ...
- SSE图像算法优化系列三十二:Zhang\Guo图像细化算法的C语言以及SIMD指令优化
二值图像的细化算法也有很多种,比较有名的比如Hilditch细化.Rosenfeld细化.基于索引表的细化.还有Opencv自带的THINNING_ZHANGSUEN.THINNING_GUOHALL ...
- Dubbo本地存根是什么,Dubbo本地伪装又是什么?
真正的大师永远怀着一颗学徒的心 哈喽!大家好,我是小奇,一位程序员界的学徒 小奇打算以轻松幽默的对话方式来分享一些技术,如果你觉得通过小奇的文章学到了东西,那就给小奇一个赞吧 前言 书接上回,昨天打了 ...
- 用C语言实现井字棋(人人/AI人机)--完结版
目录 用C语言实现井字棋(人人/AI人机)--完结版 BUG与优化3: 1. 修改了step的计算方法,每个玩家玩完就加一次step 2. 改变了电脑下棋的逻辑,每个玩家玩完之后都跳过这次循环 源码: ...