科技的力量!!!!!!我德意志科技天下第一!!!

这是一篇需要一点儿科技的题解,但实际上这个科技我认为甚至算不上科技,太 simple 了。

首先是推柿子:

\[\sum_{i=1}^n\sum_{j=1}^n\gcd(i,j)^{i+j}
\]
\[\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^n[\gcd(i,j)=d]d^{i+j}
\]
\[\sum_{d=1}^n\sum_{i=1}^{\lfloor \frac n d \rfloor}\sum_{j=1}^{\lfloor \frac n d \rfloor}[\gcd(i,j)=1](d^d)^{i+j}
\]
\[\sum_{d=1}^n\sum_{i=1}^{\lfloor \frac n d \rfloor}\sum_{j=1}^{\lfloor \frac n d \rfloor}\sum_{k|i,k|j}\mu(k)(d^d)^{i+j}
\]
\[\sum_{d=1}^n\sum_{k=1}^{\lfloor \frac n d \rfloor}\sum_{i=1}^{\lfloor \frac n {dk} \rfloor}\sum_{j=1}^{\lfloor \frac n {dk} \rfloor
}\mu(k)(d^{dk})^{i+j}\]

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

特别的,当 \(d=1\) 时,\(f(1,n)=n^2\)

否则上面那玩意儿就是:

\[(\sum_{i=1}^nd^i)^2
\]

等比数列求和,在 \(O(\log n)\) 的时间内算出来。

回到原柿:

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

考虑将 \((d^d)^k\) 带入 \(f\)。可以发现 \(f\) 只与 \(d^d\) 的若干次方有关,并且这个幂的上界是 \(O(k \times \lfloor \frac n {dk} \rfloor)=O(n)\)。

考虑对于所有的 \(d^d\) 预处理光速幂数组。可以参考这里,复杂度是 \(O(\sqrt [4] {lim})-O(1)\)。本题的 \(lim\) 为 \(1.5 \times 10^6\),不过实际上当 \(d=1\) 时不需要光速幂数组,所以实际上上界不到 \(10^6\)。别小看这一点,\(2^{20}>10^6\),这导致了空间和时间复杂度得到了改善。

于是我们发现唯一的问题是求 \((d^d)^k-1\) 的逆元。我们使用离线求逆元,这里使用的是封装好的离线求逆元。

以及,这个屑题卡空间,所以我们对 \([1,n]\) 分成若干段,对每一段使用离线求逆元和光速幂。离线求逆元当缓存满了的时候需要清空。

我们发现,每段的长度最好是 \(8\),因为离线求逆元最多只会执行 \(10^5\) 次,且光速幂的预处理不会炸空间。还有一个好处就是,这使得离线求逆元的缓存区很短,能够卡进执行文件的缓存,大大降低了常数。

总复杂度为 \(O(n\sqrt [4] {n}+n\ln n)\)。

优化1:只枚举 \(\mu(k) \neq 0\) 的 \(k\),常数降低。

优化2:当 \(d\) 较大时,能够与其匹配的 \(k\) 过少,此时使用快速幂比光速幂更优。

不过不知道为啥只跑了 1.16s,跑得飞快。。。

code:

  1. #include<cstdio>
  2. #include<vector>
  3. typedef unsigned uint;
  4. typedef __uint128_t L;
  5. typedef unsigned long long ull;
  6. const uint M=1.5e6+5;
  7. uint P,top,pri[M],mu[M];bool zhi[M];
  8. struct FastMod{
  9. ull b,m;
  10. FastMod(ull b):b(b),m(ull((L(1)<<64)/b)){}
  11. friend inline ull operator%(const ull&a,const FastMod&mod){
  12. ull r=a-(L(mod.m)*a>>64)*mod.b;
  13. return r>=mod.b?r-mod.b:r;
  14. }
  15. }mod(2);
  16. struct Pow{
  17. std::vector<uint>p1,p2,p3,p4;
  18. inline void clear(){
  19. std::vector<uint>().swap(p1);std::vector<uint>().swap(p2);
  20. std::vector<uint>().swap(p3);std::vector<uint>().swap(p4);
  21. }
  22. inline void init(register uint x){
  23. register uint i;
  24. p1.reserve(33);p2.reserve(33);p3.reserve(33);p4.reserve(33);
  25. p1[0]=p2[0]=p3[0]=p4[0]=1;
  26. for(p1[1]=x,i=2;i<=32;++i)p1[i]=1ull*p1[i-1]*x%mod;
  27. for(x=p2[1]=p1[32],i=2;i<=32;++i)p2[i]=1ull*p2[i-1]*x%mod;
  28. for(x=p3[1]=p2[32],i=2;i<=32;++i)p3[i]=1ull*p3[i-1]*x%mod;
  29. for(x=p4[1]=p3[32],i=2;i<=32;++i)p4[i]=1ull*p4[i-1]*x%mod;
  30. }
  31. inline uint pow(const uint&x){
  32. return 1ull*p1[x&31]*p2[x>>5&31]%mod*p3[x>>10&31]%mod*p4[x>>15&31]%mod;
  33. }
  34. Pow(){
  35. clear();
  36. }
  37. }p[M>>1];
  38. inline uint pow(uint a,uint b){
  39. uint ans=1;
  40. for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;
  41. return ans;
  42. }
  43. inline void sieve(const uint&M){
  44. register uint i,j,x;mu[1]=1;
  45. for(i=2;i<=M;++i){
  46. if(!zhi[i])mu[pri[++top]=i]=-1;
  47. for(j=1;j<=top&&(x=i*pri[j])<=M;++j){
  48. zhi[x]=true;if(!(i%pri[j]))break;mu[x]=-mu[i];
  49. }
  50. }
  51. }
  52. inline uint calc(const uint&d,const uint&D,const uint&len,const uint&k,const uint&inv){
  53. uint S=(1ull*D*p[d].pow(len*k)%mod-p[d].pow(k)+P)*inv%mod;
  54. return 1ull*S*S%mod;
  55. }
  56. struct GetAns{
  57. uint ans,len,d[131073],k[131073],l[131073],f[131073],S[131073];bool o[131073];
  58. inline void flush(){
  59. uint i,s;if(!len)return;
  60. for(i=1;i<=len;++i)S[i]=1ull*S[i-1]*f[i]%mod;s=pow(S[len],P-2);
  61. do{
  62. if(o[len])ans=(ans+calc(d[len],f[len]+1,l[len],k[len],1ull*s*S[len-1]%mod))%mod;
  63. else ans=(ans+P-calc(d[len],f[len]+1,l[len],k[len],1ull*s*S[len-1]%mod))%mod;
  64. s=1ull*s*f[len]%mod;
  65. }while(--len);
  66. }
  67. inline void Insert(const uint&cd,const uint&ck,const uint&cl,const uint&cf,const bool&co){
  68. ++len;d[len]=cd;k[len]=ck;l[len]=cl;f[len]=cf;o[len]=co;
  69. if(!(len&131071))flush();
  70. }
  71. }q;
  72. inline uint Solve(const uint&n){
  73. const uint&lim4=n/4,&lim3=n/3,lim2=n/2;
  74. register uint i,k,x,ans=0,lst=2;q.ans=q.len=0;
  75. for(i=1;i<=n;++i){
  76. if(mu[i]==1)ans=(ans+1ull*(n/i)*(n/i))%mod;
  77. else if(mu[i])ans=(ans+P-1ull*(n/i)*(n/i)%mod)%mod;
  78. }
  79. for(i=2;(i<<1)<=n;++i){
  80. if(!(i&7)){
  81. q.flush();while(lst^i)p[lst++].clear();
  82. }
  83. p[i].init(pow(i,i));
  84. for(k=1;i*k<=n;++k){
  85. if(mu[k]){
  86. x=p[i].pow(k)-1;
  87. if(!x){
  88. if(mu[k]==1)ans=(ans+1ull*(n/(i*k))*(n/(i*k)))%mod;
  89. else if(mu[k])ans=(ans+P-1ull*(n/(i*k))*(n/(i*k))%mod)%mod;
  90. }
  91. else q.Insert(i,k,n/(i*k),x,mu[k]==1);
  92. }
  93. }
  94. }
  95. q.flush();while(lst^i)p[lst++].clear();
  96. for(ans=(ans+q.ans)%mod;i<=n;++i)k=pow(i,i),ans=(ans+1ull*k*k)%mod;
  97. return ans;
  98. }
  99. signed main(){
  100. uint T,n1,n2,m1,m2;q.S[0]=1;
  101. scanf("%u",&T);
  102. if(T==1)scanf("%u%u",&n1,&m1),sieve(n1),mod=FastMod(P=m1),printf("%u",Solve(n1));
  103. else{
  104. scanf("%u%u%u%u",&n1,&m1,&n2,&m2);
  105. sieve(n1>n2?n1:n2);
  106. mod=FastMod(P=m1);printf("%u\n",Solve(n1));
  107. mod=FastMod(P=m2);printf("%u",Solve(n2));
  108. }
  109. }

闲话:这个 \(O(n\log n)\) 可比官方题解的 \(O(n\log n)\) 靠谱多了。

LGP6825题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

随机推荐

  1. hr虚线

    转载请注明来源:https://www.cnblogs.com/hookjc/ <hr size="1" noshade="noshade" style= ...

  2. Ubuntu18修改/迁移mysql5.7数据存放路径

    1.停止mysql服务 sudo service mysql stop 2.修改mysql配置文件,一般是 /etc/mysql/my.cnf,或者/etc/mysql/mysql.conf.d/my ...

  3. ios真机弱网测试

    一.开启苹果手机开发者选项 首先你需要将iPhone和一台Mac电脑相连接,然后在Mac上打开Xcode开发工具,此时你iPhone的设置里就会出现"开发者"这个选项了. 二.进入 ...

  4. 如何从0到1设计一个类Dubbo的RPC框架

    之前分享了如何从0到1设计一个MQ消息队列,今天谈谈"如何从0到1设计一个Dubbo的RPC框架",重点考验: 你对RPC框架的底层原理掌握程度. 以及考验你的整体RPC框架系统设 ...

  5. linux中可以查看端口占用的方法

    在自己搭建的服务器中,经常容易出现端口被占用的问题,那么怎么知道自己的端口是否被占用了呢? 可以使用下面的方法: linux中可以查看端口占用的方法. netstat -ant | grep 80 ( ...

  6. Solution Set - Stirling 数相关杂题

      <好多题的题解>   「洛谷 P5408」第一类斯特林数·行   根据结论 \[x^{\overline{n}}=\sum_i{n\brack i}x^i, \] 我们只需要求出 \( ...

  7. 我们一起来学Shell - shell的条件判断

    文章目录 Shell 条件测试语法 符号说明 Shell 测试表达式 文件测试表达式 字符串测试表达式 整数操作符 逻辑操作符 测试表达式的区别总结 Shell 条件判断之if语句 单分支 IF 条件 ...

  8. Redis原理再学习04:数据结构-哈希表hash表(dict字典)

    哈希函数简介 哈希函数(hash function),又叫散列函数,哈希算法.散列函数把数据"压缩"成摘要,有的也叫"指纹",它使数据量变小且数据格式大小也固定 ...

  9. web安全之快速反弹 POST 请求

    在 CTF Web 的基础题中,经常出现一类题型:在 HTTP 响应头获取了一段有效期很短的 key 值后,需要将经过处理后的 key 值快速 POST 给服务器,若 key 值还在有效期内,则服务器 ...

  10. Renix签名字段详解——网络测试仪实操

    一.签名字段简介 在添加/修改流量时,会有一个签名字段选项 (1)勾选以后,RENIX软件在发流时,会把每个报文的Payload(净荷)的最后18字节修改为特殊的值,用来统计流的时延.丢包等内容 (2 ...