https://scut.online/p/354

跟多项式一点关系都没有。

注意到其实两个多项式在1处求值,那么就是他们的系数加起来。

列一列发现系数就是n以内两两求gcd的值,还自动把0去掉了。

那么就是

\(\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}gcd(i^2,j^2)\)

这种情况就要枚举g但是为了方便我们也是枚举g而不是g平方

\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}[gcd(i^2,j^2)==g^2]\)

列一列gcd的分解式发现其实可以把平方约分掉

\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}[gcd(i,j)==g]\)

二话不说除以g

\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}[gcd(i,j)==1]\)

套上反演

\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{k|gcd(i,j)}\mu(k)\)

\(\sum\limits_{g=1}^{n}g^2\sum\limits_{k=1}^{n}\mu(k){\lfloor\frac{n}{gk}\rfloor}^{2}\)

枚举T

\(\sum\limits_{T=1}^{n}{\lfloor\frac{n}{T}\rfloor}^{2}\sum\limits_{g|T}g^2\mu(\frac{T}{g})\)

假如搞得出后面那个狄利克雷卷积的前缀和,那么可以分块回答,看看复杂度刚刚够的样子。

后面那个是

\(\sum\limits_{g|T}g^2\mu(\frac{T}{g})\)

也就是

\(id^2*\mu\)

嗷神提示卷一个东西,恒等函数\(I(n)=1\)

\((id^2*\mu)*I\)

结合律

\(id^2*(\mu*I)\)

后面那个就是

\(id^2*(\epsilon)\)

这个东西展开就是

\(\sum\limits_{g|T}g^2[\frac{T}{g}==1]\)

\(T^2\)

也就是说卷积之后的前缀和是\(s_2\),而恒等函数的前缀和就是\(s_0\)

上一波杜教筛就可以了

测试发现unorder_map和cc_hash_table差异非常小。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
//int f = 0;
char c;
do {
c = getchar();
/*if(c == '-')
f = 1;*/
} while(c < '0' || c > '9');
do {
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
} while(c >= '0' && c <= '9');
//return f ? -x : x;
return x;
} inline void _write(int x) {
if(x > 9)
_write(x / 10);
putchar(x % 10 + '0');
} inline void write(int x) {
if(x < 0) {
putchar('-');
x = -x;
}
_write(x);
putchar('\n');
} /*void TestCase(int ti); int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
//freopen("Yinku.out","w",stdout);
#endif // Yinku
int T = 1;
for(int ti = 1; ti <= T; ti++)
TestCase(ti);
}*/ /*--- ---*/ const int mod = 998244353;
const int inv2 = (mod + 1) >> 1;
const int MAXN = 1.5e7; int pri[MAXN + 1];
int &pritop = pri[0];
int f[MAXN + 1];
int pk[MAXN + 1]; void sieve(int n = MAXN) {
pk[1] = 1;
f[1] = 1;
for(int i = 2; i <= n; i++) {
if(!pri[i]) {
pri[++pritop] = i;
pk[i] = i;
f[i] = (1ll * i * i - 1ll) % mod;
}
for(int j = 1; j <= pritop; j++) {
int &p = pri[j];
int t = i * p;
if(t > n)
break;
pri[t] = 1;
if(i % p) {
pk[t] = p;
f[t] = 1ll * f[i] * f[p] % mod;
} else {
pk[t] = pk[i] * p;
if(pk[t] == t) {
f[t] = 1ll * f[i] * p % mod * p % mod;
} else {
f[t] = 1ll * f[t / pk[t]] * f[pk[t]] % mod;
}
break;
}
}
}
for(int i = 1; i <= n; i++) {
f[i] = f[i - 1] + f[i];
if(f[i] >= mod)
f[i] -= mod;
}
} /*inline int qpow(ll x, int n) {
ll res = 1;
while(n) {
if(n & 1) {
res *= x;
if(res >= mod)
res %= mod;
}
x *= x;
if(x >= mod)
x %= mod;
n >>= 1;
}
return res;
}*/ const int inv6 = 166374059; //qpow(6, mod - 2); inline int s2(ll n) {
if(n >= mod)
n %= mod;
ll tmp = n * (n + 1);
if(tmp >= mod)
tmp %= mod;
tmp *= n * 2 + 1 ;
if(tmp >= mod)
tmp %= mod;
tmp *= inv6;
if(tmp >= mod)
tmp %= mod;
return tmp;
} unordered_map<ll, int> Sf; inline int F(ll n) {
if(n <= MAXN)
return f[n];
if(Sf.count(n))
return Sf[n];
ll ret = s2(n);
for(ll l = 2, r; l <= n; l = r + 1) {
ll t = n / l;
r = n / t;
ret -= (r - l + 1) % mod * F(t) % mod;
if(ret < 0)
ret += mod;
}
return Sf[n] = ret;
} inline int S(ll n) {
ll res = 0;
for(ll l = 1, r; l <= n; l = r + 1) {
ll t = n / l;
r = n / t;
ll tmp = F(r) - F(l - 1);
if(tmp < 0)
tmp += mod;
if(t >= mod)
t %= mod;
t *= t;
if(t >= mod)
t %= mod;
tmp *= t;
if(tmp >= mod)
tmp %= mod;
res += tmp;
if(res >= mod)
res -= mod;
}
return res;
} int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
//freopen("Yinku.out","w",stdout);
#endif // Yinku
sieve();
int T = read();
while(T--) {
write(S(read()));
}
}

但是好像发现一个问题,别人都是欧拉函数的?

\(\sum\limits_{g=1}^{n}g^2\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}\sum\limits_{i=1}^{\lfloor\frac{n}{g}\rfloor}[gcd(i,j)==1]\)

这里内部记为

\(S(n)=\sum\limits_{i=1}^{n}\sum\limits_{i=1}^{n}[gcd(i,j)==1]\)

n以内互质对的个数?那么枚举较大的那个,小的那个要和他互质,就是欧拉函数,大小互换多了一倍,其中(1,1)重复去掉一个

\(S(n)=-1+2\sum\limits_{i=1}^{n}\varphi(i)\)

所以原式就是

\(\sum\limits_{g=1}^{n}g^2S(\lfloor\frac{n}{g}\rfloor)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll; inline ll read() {
ll x = 0;
//int f = 0;
char c;
do {
c = getchar();
/*if(c == '-')
f = 1;*/
} while(c < '0' || c > '9');
do {
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
} while(c >= '0' && c <= '9');
//return f ? -x : x;
return x;
} inline void _write(int x) {
if(x > 9)
_write(x / 10);
putchar(x % 10 + '0');
} inline void write(int x) {
if(x < 0) {
putchar('-');
x = -x;
}
_write(x);
putchar('\n');
} /*void TestCase(int ti); int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
//freopen("Yinku.out","w",stdout);
#endif // Yinku
int T = 1;
for(int ti = 1; ti <= T; ti++)
TestCase(ti);
}*/ /*--- ---*/ const int mod = 998244353;
const int inv2 = (mod + 1) >> 1;
const int MAXN = 1.6e7; int pri[MAXN + 1];
int &pritop = pri[0];
int phi[MAXN + 1]; void sieve(int n = MAXN) {
phi[1] = 1;
for(int i = 2; i <= n; i++) {
if(!pri[i]) {
pri[++pritop] = i;
phi[i] = i - 1;
}
for(int j = 1; j <= pritop; j++) {
int &p = pri[j];
int t = i * p;
if(t > n)
break;
pri[t] = 1;
if(i % p) {
phi[t] = phi[i] * phi[p];
} else {
phi[t] = phi[i] * p;
break;
}
}
}
for(int i = 1; i <= n; i++) {
phi[i] += phi[i - 1];
if(phi[i] >= mod)
phi[i] -= mod;
}
} /*inline int qpow(ll x, int n) {
ll res = 1;
while(n) {
if(n & 1) {
res *= x;
if(res >= mod)
res %= mod;
}
x *= x;
if(x >= mod)
x %= mod;
n >>= 1;
}
return res;
}*/ inline int s1(ll n) {
if(n >= mod)
n %= mod;
return n * (n + 1) % mod * inv2 % mod;
} const int inv6 = 166374059; //qpow(6, mod - 2);
inline int s2(ll n) {
if(n >= mod)
n %= mod;
ll tmp = n * (n + 1);
if(tmp >= mod)
tmp %= mod;
tmp *= n * 2 + 1 ;
if(tmp >= mod)
tmp %= mod;
tmp *= inv6;
if(tmp >= mod)
tmp %= mod;
return tmp;
} unordered_map<ll, int> Sphi; inline int Phi(ll n) {
if(n <= MAXN)
return phi[n];
if(Sphi.count(n))
return Sphi[n];
int ret = s1(n);
for(ll l = 2, r, t; l <= n; l = r + 1) {
t = n / l;
r = n / t;
ret -= (r - l + 1) % mod * Phi(t) % mod;
if(ret < 0)
ret += mod;
}
return Sphi[n] = ret;
} inline int S(ll n) {
return (2 * Phi(n) - 1) % mod;
} inline int Ans(ll n) {
int res = 0;
for(ll l = 1, r, t; l <= n; l = r + 1) {
t = n / l;
r = n / t;
ll tmp = s2(r) - s2(l - 1);
if(tmp < 0)
tmp += mod;
tmp *= S(t);
if(tmp >= mod)
tmp %= mod;
res += tmp;
if(res >= mod)
res -= mod;
}
return res;
} int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
//freopen("Yinku.out","w",stdout);
#endif // Yinku
sieve();
int T = read();
while(T--) {
write(Ans(read()));
}
}

SCUT - 354 - CC的简单多项式 - 杜教筛的更多相关文章

  1. SCUT - 114 - 作业之数学篇 - 杜教筛

    https://scut.online/p/114 \(A(n)=\sum\limits_{i=1}^{n} \frac{lcm(i,n)}{gcd(i,n)}\) \(=\sum\limits_{i ...

  2. 【Luogu3768】简单的数学题(莫比乌斯反演,杜教筛)

    [Luogu3768]简单的数学题(莫比乌斯反演,杜教筛) 题面 洛谷 \[求\sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)\] $ n<=10^9$ 题解 很明显的把\( ...

  3. P3768 简单的数学题 杜教筛+推式子

    \(\color{#0066ff}{ 题目描述 }\) 由于出题人懒得写背景了,题目还是简单一点好. 输入一个整数n和一个整数p,你需要求出(\(\sum_{i=1}^n\sum_{j=1}^n ij ...

  4. 「洛谷P3768」简单的数学题 莫比乌斯反演+杜教筛

    题目链接 简单的数学题 题目描述 输入一个整数n和一个整数p,你需要求出 \[\sum_{i=1}^n\sum_{j=1}^n (i\cdot j\cdot gcd(i,j))\ mod\ p\]  ...

  5. 【Luogu】P3768简单的数学题(杜教筛)

    题目链接 emm标题全称应该叫“莫比乌斯反演求出可狄利克雷卷积的公式然后卷积之后搞杜教筛” 然后成功地困扰了我两天qwq 我们从最基本的题意开始,一步步往下推 首先题面给出的公式是$\sum\limi ...

  6. 【luogu3768】简单的数学题 欧拉函数(欧拉反演)+杜教筛

    题目描述 给出 $n$ 和 $p$ ,求 $(\sum\limits_{i=1}^n\sum\limits_{j=1}^nij\gcd(i,j))\mod p$ . $n\le 10^{10}$ . ...

  7. loj#6229. 这是一道简单的数学题 (??反演+杜教筛)

    题目链接 题意:给定\(n\le 10^9\),求:\(F(n)=\sum_{i=1}^n\sum_{j=1}^i\frac{\mathrm{lcm}(i,j)}{\mathrm{gcd}(i,j)} ...

  8. [luogu3768] 简单的数学题 [杜教筛]

    题面: 传送门 实际上就是求: 思路: 看到gcd就先反演一下,过程大概是这样: 明显的一步反演 这里设,S(x)等于1到x的和 然后把枚举d再枚举T变成先枚举T再枚举其约数d,变形: 后面其中两项展 ...

  9. 洛谷P3768 简单的数学题 【莫比乌斯反演 + 杜教筛】

    题目描述 求 \[\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{n} i*j*gcd(i,j) \pmod{p}\] \(n<=10^{10}\),\(p\) ...

随机推荐

  1. Struts 2简单实例

    Struts 2简单实例 参考: [java开发系列]—— struts2简单入门示例 - xingoo - 博客园https://www.cnblogs.com/xing901022/p/39616 ...

  2. winform 添加帮助按钮

    1. 添加提示信息 新建个窗体项目,项目名称为WinFormUI,解决方案名称为WinFormWithHelpDoc.删除默认创建的Form1,新建窗体MainForm,设置相关属性.我们要完成的效果 ...

  3. python生成excel格式座位表

    脚本分两个文件: 1.生成二维随机列表:GenerateLocaltion.py 2.将列表导入excel文件:CreateExcel.py 先上GenerateLocaltion.py: impor ...

  4. NO3:步履蹒跚-完成第一章节学习

    第一章小记: 每个C程序都要求有一个main()函数(多于一个main()函数是不合法的(已犯错:在VS 2010一个项目里两个C文件都有main函数,不能编译通过,必须删除一个文件,永记)).mai ...

  5. windows 7下mingw+msys编译ffmpeg

      windows 7下mingw+msys编译ffmpeg   1-->下载安装MingW,mingw-get-inst-20120426.exe  http://sourceforge.ne ...

  6. What is Photon Server?

    http://blog.csdn.net/menuconfig/article/details/8215033 Photon Server是一套套裝的遊戲伺服器,以往開發線上遊戲都必需自行花費大筆的研 ...

  7. Oracle 12C 新特性之扩展数据类型(extended data type)

    Oracle 12C 新特性-扩展数据类型,在12c中,与早期版本相比,诸如VARCHAR2, NAVARCHAR2以及 RAW这些数据类型的大小会从4K以及2K字节扩展至32K字节.只要可能,扩展字 ...

  8. 11g RAC 如何备份OCR,利用备份恢复OCR,ocrdump

    OCR备份 OCR的备份有2种方式,自动备份和手工备份. 自动备份策略: Oracle Clusterware 每隔4小时,CRSD 进程会自动对OCR 进行一次备份,在任意时刻,oracle 总会保 ...

  9. VisualGDB系列9:配置VS直接通过SSH方式访问Linux项目

    根据VisualGDB官网(https://visualgdb.com)的帮助文档大致翻译而成.主要是作为个人学习记录.有错误的地方,Robin欢迎大家指正. 本文介绍如何使用VS和VisualGDB ...

  10. openStack kvm 虚拟机CPU颗粒化控制

    前一篇理解cpu topology对CPU Topology进行了学习总结,这里想总结下OpenStack下vCPU与pCPU常用的的绑定方式. 在尝试这些绑定之前,尤其是处理NUMA架构时还是建议看 ...