博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[LOJ572]Misaka Network 与求和
阅读量:5221 次
发布时间:2019-06-14

本文共 3437 字,大约阅读时间需要 11 分钟。

1464677-20190419110944874-273798928.png


题解

题解

题目让求\(\sum_{i=1}^{n}\sum_{j=1}^{n}f(gcd(i,j))^k\)

\(f\)代表次大质因子
先反演化简一波式子
\(\sum_{t=1}^{n}f(t)^k\sum_{i=1}^{n}\sum_{j=1}^{n}[gcd(i,j)]= t]\\ \sum_{t=1}^{n}f(t)^k\sum_{d=1}^{\frac{n}{t}}\mu(d)\lfloor\frac{n}{dt}\rfloor^2\\ \sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor^2\sum_{d|T}\mu(d)f(\frac{T}{d})^k\)
然后就可以去筛函数\(F(T)=\sum_{d|T}\mu(d)f(\frac{T}{d})^k\)
那么来考虑这玩意儿在非线性时间内怎么筛出来?
可以发现这个函数是用狄利克雷卷积来定义的,而且这个函数还包括了\(\mu\),所以可以考虑杜教筛
考虑用\(I\)\(F\)做狄利克雷卷积
\(I * \mu * f=(I * \mu)*f=e*f=f\)
所以我们在杜教筛中要快速求的狄利克雷卷积后的前缀和就是求\(f\)的前缀和了
\(f\)代表了次大质因子
所以可以考虑用\(min25\)筛来处理
具体做法就是先处理出\(g(i)\)表示\(\le i\)的质数的个数
然后考虑每个质数\(p_i\)的贡献
只有当分解到只剩下两个质数的时候再计算贡献
\(p_i\)的贡献就是当前所有比\(p_i\)大的质数的个数\(\times p_i^k\)
然后在枚举最小质因数的若干次方的时候顺便计算最大质因数和次大值因数相同的情况
具体就是这样筛的

int S(int x , int j) {    if(x <= 1 || pri[j] > x) return 0 ;     int ret = prik[j - 1] * (g[Gid(x)] - j + 1) ;    // 只剩下p[j-1]和另外一个比ta大的质数    for(int i = j ; i <= pnum && pri[i] * pri[i] <= x ; i ++) {        LL p1 = pri[i] , p2 = pri[i] * pri[i] ;        for( ; p2 <= x ; p1 = p2 , p2 *= pri[i] )             ret += S(x / p1 , i + 1) + prik[i] /*最大质因数和次大质因数相同的数 */;    }    return ret ;}

总复杂度\(O(n^{\frac{3}{4}})\)

有点卡常数

代码

#include
#include
#include
#include
# define LL long long# define uit unsigned int const int M = 200005 ;using namespace std ;bool notp[M] , vis1[M] , vis2[M] ;int n , m , sz , idk , pnum ;int w[M] , id1[M] , id2[M] , pri[M] ;uit ans , prik[M] , g[M] , f1[M] , f2[M] ;inline int Gid(int x) { return (x <= sz) ? id1[x] : id2[n / x] ;}inline uit Fpw(uit Base , int k) { uit temp = 1 ; while(k) { if(k & 1) temp = temp * Base ; Base = Base * Base ; k >>= 1 ; } return temp ;}inline void presolve(int n) { for(int i = 2 ; i <= n ; i ++) { if(!notp[i]) pri[++pnum] = i , prik[pnum] = Fpw((uit)i , idk) ; for(int j = 1 ; j <= pnum && i * pri[j] <= n ; j ++) { notp[i * pri[j]] = true ; if(i % pri[j] == 0) break ; } }}uit S(int x , int j) { if(x <= 1 || pri[j] > x) return 0 ; uit ret = prik[j - 1] * (g[Gid(x)] - j + 1) ; for(int i = j ; i <= pnum && pri[i] * pri[i] <= x ; i ++) { LL p1 = pri[i] , p2 = pri[i] * pri[i] ; for( ; p2 <= x ; p1 = p2 , p2 *= pri[i] ) ret += S(x / p1 , i + 1) + prik[i] ; } return ret ;}inline uit Calc(int n) { if(vis2[Gid(n)]) return f2[Gid(n)] ; f2[Gid(n)] = S(n , 1) ; vis2[Gid(n)] = true ; return f2[Gid(n)] ;}uit Solve(int n) { if(n <= 1) return 0 ; if(vis1[Gid(n)]) return f1[Gid(n)] ; uit ret = Calc(n) + g[Gid(n)] ; for(int l = 2 , r ; l <= n ; l = r + 1) { r = n / (n / l) ; ret -= (r - l + 1) * Solve(n / l) ; } vis1[Gid(n)] = true ; f1[Gid(n)] = ret ; return ret ;}int main() { scanf("%d%d",&n,&idk) ; sz = sqrt(n) ; presolve(sz) ; for(int l = 1 , r ; l <= n ; l = r + 1) { r = n / (n / l) ; w[++m] = n / l ; if(w[m] <= sz) id1[w[m]] = m ; else id2[n / w[m]] = m ; g[m] = w[m] - 1 ; } for(int j = 1 ; j <= pnum ; j ++) for(int i = 1 ; i <= m && pri[j] * pri[j] <= w[i] ; i ++) g[i] -= g[Gid(w[i] / pri[j])] - j + 1 ; for(int l = 1 , r ; l <= n ; l = r + 1) { r = n / (n / l) ; ans += (uit)(n / l) * (n / l) * (Solve(r) - Solve(l - 1)) ; } printf("%u\n",ans) ; return 0 ;}

转载于:https://www.cnblogs.com/beretty/p/10734946.html

你可能感兴趣的文章
201571030319 四则运算
查看>>
RestTemplate 调用本地服务 connection refused
查看>>
.NET方向高级开发人员面试时应该事先考虑的问题
查看>>
台达PLC modbus 不支持04功能码
查看>>
python学习笔记--装饰器
查看>>
发布一个JavaScript工具类库jutil,欢迎使用,欢迎补充,欢迎挑错!
查看>>
discuz 常用脚本格式化数据
查看>>
MS CRM 2011 创建基于Fetch的报表 -- 进阶版
查看>>
洛谷P2777
查看>>
PHPStorm2017设置字体与设置浏览器访问
查看>>
循环-12. 打印九九口诀表(15)
查看>>
SQL查询总结 - wanglei
查看>>
安装cocoa pods时出现Operation not permitted - /usr/bin/xcodeproj的问题
查看>>
makefile中使用变量
查看>>
GIT笔记:将项目发布到码云
查看>>
JavaScript:学习笔记(7)——VAR、LET、CONST三种变量声明的区别
查看>>
JavaScript 鸭子模型
查看>>
PHP典型功能与Laravel5框架开发学习笔记
查看>>
SQL Server 如何查询表定义的列和索引信息
查看>>
项目上传到github上
查看>>