这道题目真的是将必修一的抽象函数用得淋漓尽致啊。

首先观察 \(f(a,b)=f(b,a)\),嗯,并没有什么鸟用,所以我们先不管他。

然后,就盯着 \(b\times f(a,a+b)=(a+b)\times f(a,b)\) 发呆吧。

我们还是可以发现:

\[\frac{f(a,a+b)}{a+b}=\frac{f(a,b)}{b}
\]

熟悉课内题目的同学不难想到造个同构函数:

\[g(a,b)=\frac{f(a,b)}{b}
\]

然后发现:

\[g(a,b)=g(a,a+b)
\]

诶,这怎么那么像求 \(\gcd\) 时的更相减损术?

实际上我们可以得到:

\[g(a,b)=g(a,a+b)=g(a+b,a)=g(b,a)
\]

怎么样,很震惊吧,我也是这么认为的。

那么我们更改 \(f(a,b)\) 这个值,相当于更改 \(g(a,b)\) 的值,又通过更相减损术可以得到其更改 \(g(x,y)\) 的值当且仅当 \(\gcd(x,y)=\gcd(a,b)\)。

通过这个我们发现一个题目的性质,那就是:我们可以将任意 \(f(a,b)\) 的更改以及求贡献都可以算到 \(f(\gcd(a,b),\gcd(a,b))\) 中,在物理中这被光荣地称为等效替代法

然后通过手玩:

\[f(d,d)\times 2d=f(d,2d)\times d\\
f(d,2d)\times 3d=f(d,3d)\times 2d
\]

不难得到:\(f(d,kd)=\frac{k}{k-1}f(d,(k-1)d)=\frac{k}{k-1}\times\frac{k-1}{k-2}f(d,(k-2)d)=\dots=kf(d,d)\)

那么同理可得,当 \(\gcd(k_1,k_2)=1\) 时,\(f(k_1d,k_2d)=k_1\times k_2\times f(d,d)\)

那么对于更改 \(f(a,b)\) 怎么更改到 \(f(d,d)\) 呢?

有了上面的公式这个也变得简单了起来,具体而言是:

\[f(a,b)=f(d,d)\times\frac{ab}{d^2}
\]

考虑题目要求:

\[\sum_{i=1}^n\sum_{j=1}^n f(i,j)
\]

那么我们可以用上面的式子进行转化:

\[\sum_{i=1}^n\sum_{j=1}^n \frac{ij}{\gcd(i,j)^2}f(\gcd(i,j),\gcd(i,j))
\]

枚举一下 \(\gcd(i,j)\) 得到:

\[\sum_{d=1}^n\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}ij\times f(d,d)[\gcd(i,j)=1]
\]

将 \(f(d,d)\) 提到前面来:

\[\sum_{d=1}^n f(d,d)\sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}ij[\gcd(i,j)=1]
\]

观察得到,后面的那一个式子可以用以下公式解决(很经典):

\[\sum_{i=1}^n[\gcd(i,n)=1]i=\frac{n\varphi(n)+[n=1]}{2}
\]

我们考虑跟这个式子有什么关系:

\[\begin{align}
&&&\sum_{i=1}^n\sum_{j=1}^n ij[\gcd(i,j)=1]\\
&&=&\sum_{i=1}^ni^2[\gcd(i,i)=1]+2\sum_{1\leq i<j\leq n} ij[\gcd(i,j)=1]\\
&&=&1+2\sum_{j=2}^n\frac{j^2\times\varphi(j)}{2}\\
&&=&\sum_{j=1}^nj^2\varphi(j)\\
&&=&\sum_{i=1}^ni^2\varphi(i)
\end{align}
\]

记 \(S(n)=\sum_{i=1}^ni^2\varphi(i)\),于是我们的式子变成了这个:

\[\sum_{d=1}^n S(\lfloor\frac n d\rfloor)f(d,d)
\]

注意到:\(S(n)\) 可以 \(\mathcal{O}(n)\) 预处理,而这个式子又是一个典型的整除分块,我们就可以在查询的时候 \(\mathcal{O}(m\sqrt n)\) 的时间内回答了。

但是,由于会更改,这个 \(f(d,d)\) 的值还是会是时间复杂度上升,比如说你用树状数组维护这个单点修改以及区间查询的话,时间复杂度就会变为 \(\mathcal{O}(m(\log(n)+\sqrt n\log n))\)。

那,主播主播有没有比较朴实的方法呢?

没错,我们就是要朴实的方法——分块!

怎么降时间复杂度呢,由于我们考虑的是查询的时候要 \(\mathcal{O}(1)\) 解决(指查出这个区间的和),那么我们可以把原本的序列看作一个前缀和,直接在更改的时候用分块处理这个前缀和,然后查询就是 \(\mathcal{O}(1)\) 的。

代码

总时间复杂度为 \(\mathcal{O}(n+m\sqrt n)\) 的,代码如下:

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define int long long
#define N 4000006
#define M 500005
#define P 3005
using namespace std;
const int mod = 1e9 + 7;
bool vis[N];
int prime[M],cnt,phi[N],f[N],sum[N],sum2[N];
void init(int n) {
phi[1] = 1;
for (int i = 2;i <= n;i ++) {
if (!vis[i]) prime[++cnt] = i,phi[i] = i - 1;
for (int j = 1;j <= cnt && prime[j] * i <= n;j ++) {
vis[prime[j] * i] = 1;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
for (int i = 1;i <= n;i ++) f[i] = i * i % mod;
for (int i = 1;i <= n;i ++) sum[i] = (sum[i - 1] + phi[i] * i % mod * i % mod) % mod;
for (int i = 1;i <= n;i ++) sum2[i] = (sum2[i - 1] + f[i]) % mod;
}
int gcd(int a,int b) {
return b ? gcd(b,a % b) : a;
}
int n,m,bl[N],L[P],R[P],lz[P];
void build() {
int len = ceil(sqrt(1.0 * n));
for (int i = 1;i < P;i ++) L[i] = 1145141919;
for (int i = 1;i <= n;i ++) {
int t = i / len + 1;
bl[i] = t;
R[t] = i;
L[t] = min(L[t],i);
}
R[bl[n] + 1] = 1e9;
// for (int i = 1;i <= bl[n];i ++) lz[i] = 0;
}
void update(int r,int val) {
// val = (val % mod + mod) % mod;
// cout << sum2[r] << ' ' << val << ' ' << (sum2[r] +) << '\n';
int pos = bl[r];
if (r == L[pos]) lz[pos] = (lz[pos] + val + mod) % mod;
else for (int i = r;i <= R[pos];i ++) sum2[i] = (sum2[i] + val + mod) % mod;
pos ++;
for (;R[pos] <= n;pos ++) lz[pos] = (lz[pos] + val + mod) % mod;
// cout << endl;
}
int query(int pos) {
// cout << pos << ' ' << sum2[pos] << endl;
return ((sum2[pos] + lz[bl[pos]]) % mod + mod) % mod;
}
signed main(){
init(4e6);
cin >> m >> n;
build();
for (int a,b,x,k;m --;) {
scanf("%lld%lld%lld%lld",&a,&b,&x,&k);
int t = gcd(a,b);
int ans = 0;
update(t,-f[t]);
f[t] = x / ((a / t) * (b / t));
// cout << f[t] << endl;
// cout <<2;
update(t,f[t]);
for (int l = 1,r;l <= k;l = r + 1) {
r = k / (k / l);
// cout << l << ' ' << r << ' ' << query(r) << ' ' << query(l - 1) << '\n';
ans = (ans + sum[k / l] * (query(r) - query(l - 1) + mod) % mod) % mod;
}
printf("%lld\n",ans);
}
return 0;
}
/*
6 4000000
10 2345 10000 4000000
100 2345 10000 4000000
1000 2345 10000 4000000
77 22 42494 142992 494924
94 492 92924 249294 24994
294 294 29494 2949222 949492 806651387
209058084
253769940
691839689
637913350
765583133 */

P3700 [CQOI2017] 小 Q 的表格 题目分析的更多相关文章

  1. 洛咕 P3700 [CQOI2017]小Q的表格

    洛咕 P3700 [CQOI2017]小Q的表格 神仙题orz 首先推一下给的两个式子中的第二个 \(b\cdot F(a,a+b)=(a+b)\cdot F(a,b)\) 先简单的想,\(F(a,a ...

  2. [bzoj4815] [洛谷P3700] [Cqoi2017] 小Q的表格

    Description 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理. 每当小Q不知道如何解决时,就只好向你求助.为了完成任务,小Q需要列一个表格 ...

  3. 洛谷 P3700 - [CQOI2017]小Q的表格(找性质+数论)

    洛谷题面传送门 又是一道需要一些观察的数论 hot tea-- 注意到题目中 \(b·f(a,a+b)=(a+b)·f(a,b)\) 这个柿子长得有点像求解 \(\gcd\) 的辗转相除法,因此考虑从 ...

  4. [BZOJ4815][CQOI2017]小Q的表格(莫比乌斯反演)

    4815: [Cqoi2017]小Q的表格 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 832  Solved: 342[Submit][Statu ...

  5. bzoj 4815: [Cqoi2017]小Q的表格 [数论]

    4815: [Cqoi2017]小Q的表格 题意: 单点修改,查询前缀正方形和.修改后要求满足条件f(a,b)=f(b,a), b×f(a,a+b)=(a+b)*f(a,b) 一开始sb了认为一次只会 ...

  6. 【BZOJ4815】[CQOI2017]小Q的表格(莫比乌斯反演,分块)

    [BZOJ4815][CQOI2017]小Q的表格(莫比乌斯反演,分块) 题面 BZOJ 洛谷 题解 神仙题啊. 首先\(f(a,b)=f(b,a)\)告诉我们矩阵只要算一半就好了. 接下来是\(b* ...

  7. [CQOI2017]小Q的表格(数论+分块)

    题目描述 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理.每当小Q不知道如何解决时,就只好向你求助. 为了完成任务,小Q需要列一个表格,表格有无穷多 ...

  8. [bzoj4815]: [Cqoi2017]小Q的表格

    来自FallDream的博客,未经允许,请勿转载,谢谢. 小Q是个程序员. 作为一个年轻的程序员,小Q总是被老C欺负,老C经常把一些麻烦的任务交给小Q来处理.每当小Q不知道如何解决时,就只好向你求助. ...

  9. BZOJ 4815 CQOI2017 小Q的表格 欧拉函数+分块

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4815 题意概述:要认真概述的话这个题就出来了... 分析: 首先分析题目,认真研究一下修 ...

  10. bzoj 4815: [Cqoi2017]小Q的表格【欧拉函数+分块】

    参考:http://blog.csdn.net/qq_33229466/article/details/70174227 看这个等式的形式就像高精gcd嘛-所以随便算一下就发现每次修改(a,b)影响到 ...

随机推荐

  1. POLIR-Society-Organization-Psychology-Relationship关系-Values价值: Values in a Relationship + How to Talk About it

    https://www.verywellmind.com/speaking-about-values-in-your-relationship-5191152 Theories > Social ...

  2. SciTech-Mathematics-Probability+Statistics-Statistical Proofs-[THREE types of Probability]{Subjective:Choices/Decisions/Conclusions, Theoretical, Empirical}

    Links Bayes, Empirical Bayes and Moderated Methods Empirical and theoretical prior distribution | Th ...

  3. Linux 给文件夹或者文件增加权限-九五小庞

    chmod -R 777 文件夹 参数-R是递归的意思 777表示开放所有权限   chmod 777 test.sh chmod +x 某文件 如果给所有人添加可执行权限:chmod a+x 文件名 ...

  4. 2023年6月最新全国省市区县和乡镇街道行政区划矢量边界坐标经纬度地图数据 shp geojson json

    发现个可以免费下载全国 geojson 数据的网站,推荐一下.支持全国.省级.市级.区/县级.街道/乡镇级以及各级的联动数据,支持导入矢量地图渲染框架中使用,例如:D3.Echarts等 geojso ...

  5. P6638 「JYLOI Round 1」常规

    容易把问题转换为求前缀和.设 \(p\) 为当前最大的下标使得 \(a_p \leq x\),则容易得到答案: \[\text{ans} = \sum_{i = 1}^{p}\left\lfloor\ ...

  6. Origin2022中文版如何绘制反向双轴柱状图?

    柱形图是科研中经常用到的,今天给大家分享创建反向双轴柱状图,可直观的在同一图表中展示两组正负数据,且即使两组数值差异较大也可正常显示,比文字描述更清晰 操作步骤: 1.打开Origin2022软件,在 ...

  7. Vue实现登陆时token存放到Vuex

    一.Vue实现登陆时token存放到Vuex 1.登录页面 <template> <div> <h1>登录</h1> {{ $store.state.t ...

  8. python 获取163 邮箱的邮件信息

    此案例是是获取的一个亚马逊的验证码 import time from imaplib import IMAP4_SSL import imaplib,email,datetime from lxml ...

  9. MyEMS能源管理系统后台配置-协议

    MyEMS开源能源管理系统适用于建筑.工厂.商场.医院.园区的电.水.气等能源数据采集.分析.报表,还有光伏.储能.充电桩.微电网.设备控制.故障诊断.工单管理.人工智能优化等可选功能. 本文介绍My ...

  10. MySQL里面怎么看一条sql的执行过程

    使用 EXPLAIN 查看执行计划 作用:分析查询优化器选择的执行计划,包括索引使用.表连接顺序等. 语法:EXPLAIN SELECT * FROM 表名 WHERE 条件; 输出关键字段: typ ...