对于百分之十的数据:随便过。

下面推式子:

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

令\(T=kd:\)

\[=\sum_{T=1}^n\sum_{k|T}\mu(k)\sum_{i=1}^\frac{n}{T}\sum_{j=1}^\frac{n}{T}[(\frac{T}{k})^T]^{i+j}
\]

现在的问题在于\(\sum_{i=1}^\frac{n}{T}\sum_{j=1}^\frac{n}{T}[(\frac{T}{k})^T]^{i+j}.\)

  • 线性递推

以下是@SOSCHINA大佬的思路:

设\(g(n)=\sum_{i=1}^n\sum_{j=1}^n k^s.\)

枚举\(s=i+j.\)

则有:

\[g(n)=\sum_{s=2}^{n+1}(s-1)k^s+\sum_{s=n+2}^{2n}(2n-s+1)k^s
\]
\[g(n+1)=\sum_{s=2}^{n+1}(s-1)k^s+\sum_{s=n+2}^{2n+2}(sn+3-s)k^s
\]
\[g(n+1)-g(n)=\sum_{s=n+2}^{2n}2k^s+2k^{2n+1}+k^{2n+2}
\]

第三行就是两行相减。

对第一行的解释:\([2,n+1]\)这里的数,每个数作为\(i+j\)都出现了\(x-1\)次。因为\(i\)可以取遍\([1,x-1].\)后面的那一些,\([n+2,2n]\)会发现\(i\)最大只能到\(n,\)不能再取遍\(x-1\)个值了。此时能取到的应该是\(2n-s+1\)种。

对于\(g(n+1):\)这里是把第一个式子的最后一个值移动到了后面那个式子,方便做差。

这时我们可以在小模数的情况下做到\(O(n*mod\))的预处理。

  • 化简形式

令\(x=(\frac{T}{k})^T.\)

则原式为\(\sum_{i=1}^\frac{n}{T}\sum_{j=1}^\frac{n}{T} x^{i+j}.\)

像不像一个多项式。

它就等于\((x+x^2+...x^\frac{n}{T})^2.\)

于是我们可以等比数列求和解出。

剩下的,可以做到\(O(n\log n\log mod)\)处理出整个式子。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1500001;
int mod,TT;
bitset<MAXN+1>vis;
int p[MAXN+1],mu[MAXN+1],T[MAXN+1],cnt,n,Ans;
inline int Mod(long long x){
if(x<0)return x+mod;
if(x>=mod)return x%mod;
return x;
}
inline int add(int x,int y) {return Mod(1ll*x+1ll*y+1ll*mod);}
inline int mul(int x,int y) {return Mod(1ll*x*y);}
inline int qpow(int a,int b) {
if(!b)return 1;
if(a<=1||b==1)return a;
a %= mod;
int res=1;
while(b) {
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
inline int calc(int x,int y){
if(y==1)return x;
if(x==1)return y;
int ans=x;
int inv=qpow((1-x+mod)%mod,mod-2);
int fm=(1-qpow(x,y)+mod)%mod;
ans=mul(ans,mul(fm,inv));
return ans;
}
inline int Calc(int x,int y){int ans=calc(x,y);return mul(ans,ans);}
int main() {
scanf("%d",&TT);
mu[1]=1;
int N=MAXN;
for(register int i=2; i<=N; ++i) {
if(!vis[i])p[++cnt]=i,mu[i]=-1;
for(register int j=1; j<=cnt&&i*p[j]<=N; ++j) {
vis[i*p[j]]=1;
if(i%p[j]==0)break;
mu[i*p[j]]=-mu[i];
}
}
while(TT--) {
scanf("%d%d",&n,&mod);
N=n;Ans=0;
for(register int i=1; i<=N; ++i) {
for(register int j=i,k,x; j<=N; j+=i) {
k=i;if(!mu[k])continue;
x=qpow(j/k,j);
T[j]=add(T[j],mul(mu[k],Calc(x,n/j)));
}
}
for(register int i=1; i<=n; ++i)Ans=add(Ans,T[i]),T[i]=0;
printf("%d\n",Ans);
} return 0;
}

由于这里是\(5*10^5\)的数据,所以略微卡常,但笔者通过非常不精湛的卡常技术跑到了\(3s\)以内,所以这里的时间限制我开了\(3.2s\).

对等比数列进行精细处理,可以做到\(O(n\log^2n)\)的复杂度。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN=1500000;
int mod,TT;
bitset<MAXN<<1>vis;
int p[MAXN<<1],mu[MAXN<<1],T[MAXN<<1],cnt,n,Ans;
inline int Mod(long long x){
if(x>=mod)return x%mod;
return x;
}
inline int add(int x,int y) {
return Mod(x+y+mod);
}
inline int mul(int x,int y) {
return Mod(1ll*x*y);
}
inline int qpow(int a,int b) {
if(!b)return 1;
if(a<=1||b==1)return a;
a %= mod;
int res=1;
while(b) {
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
inline int calc(int x,int y){
if(y==1)return x;
int res=calc(x,y/2);
res=add(res,mul(res,qpow(x,y/2)));
if(y&1)res=add(res,mul(x,qpow(x,y-1)));
return res;
}
inline int Calc(int x,int y){int ans=calc(x,y);return mul(ans,ans);}
signed main() {
scanf("%lld",&TT);
mu[1]=1;
int N=MAXN;
for(int i=2; i<=N; ++i) {
if(!vis[i])p[++cnt]=i,mu[i]=-1;
for(int j=1; j<=cnt&&i*p[j]<=N; ++j) {
vis[i*p[j]]=1;
if(i%p[j]==0)break;
mu[i*p[j]]=-mu[i];
}
}
while(TT--) {
scanf("%lld%lld",&n,&mod);
N=n;
Ans=0;
for(int i=1; i<=N; ++i) {
for(int j=i; j<=N; j+=i) {
int k=i;
int x=qpow(j/k,j);
if(!mu[k])continue;
T[j]=add(T[j],mul(mu[k],Calc(x,n/j)));
}
}
for(int i=1; i<=n; ++i)Ans=add(Ans,T[i]),T[i]=0;
cout<<Ans<<endl;
} return 0;
}

由于常数等原因,这分代码可以拿到\(50\)分的好成绩。但我们可以通过另一种做法将常数/复杂度降低。

另一种做法

观察:

\[\sum_{d=1}^n\sum_{k=1}^\frac{n}{d}\mu(k)\sum_{i=1}^\frac{n}{kd}\sum_{j=1}^\frac{n}{kd}d^{kd(i+j)}
\]
\[=\sum_{d=1}^n \sum_{k=1}^\frac{n}{d} \mu(k)(d^{kd}+d^{2kd}+...+d^{\frac{n}{kd}*kd=n})^2.
\]

这里同样观察式子发现可以直接算。前一部分是\(O(n\ln n)\)的\(n\)倍调和级数的复杂度,后面带上一个\(O(\log n)\)精细处理的等比数列求求和复杂度。

(代码中的优化即使不加也是可以过的)

#define __AVX__ 1
#define __AVX2__ 1
#define __SSE__ 1
#define __SSE2__ 1
#define __SSE2_MATH__ 1
#define __SSE3__ 1
#define __SSE4_1__ 1
#define __SSE4_2__ 1
#define __SSE_MATH__ 1
#define __SSSE3__ 1
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include <immintrin.h>
#include <emmintrin.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <bitset>
using namespace std;
const int MAXN=1.5e6+10;
int mod,T;
bitset<MAXN+1>vis;
int p[MAXN+1],cnt,mu[MAXN+1],N;
inline int Mod(long long a, int pp){
return a>=pp ? a%pp : a>=0 ? a : a+pp;
}
inline int add(int x,int y){return Mod( (1ll+x+y+mod-1ll),mod);}
inline int mul(int x,int y){return Mod(1ll*x*y,mod);}
void pretreatment(){
mu[1]=1;
for(int i=2;i<=MAXN;++i){
if(!vis[i])p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*p[j]<=MAXN;++j){
vis[i*p[j]]=1;
if(Mod(i,p[j])==0)break;
mu[i*p[j]]=-mu[i];
}
}
}
inline int qpow(int a,int b){
if(!b)return 1;
if(a<=1||b==1)return a;
int res=1;
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);b>>=1;
}
return res;
}
inline int calc(int x,int y){
if(y==1)return x;
int res=calc(x,y>>1);
res=add(res,mul(res,qpow(x,y>>1)));
if(y&1)res=add(res,mul(x,qpow(x,y-1)));
return res;
} inline int Calc(int x,int y){int ans=calc(x,y);return mul(ans,ans);}
int ssolve(int n,int d){
int res=0;
for(register int l=1;l<=n;++l){
if(!mu[l])continue;
res=add(res,mul(mu[l],Calc(qpow(d,l),n/l)));
}
return res;
}
int solve(int n){
int ans=0;
for(register int l=1;l<=n;l++){
ans=add(ans,ssolve(n/l,qpow(l,l)));
}
return ans;
}
signed main(){
scanf("%lld",&T);
pretreatment();
for(;T;T--){
scanf("%lld%lld",&N,&mod);
printf("%lld\n",solve(N));
}
return 0;
}

可以用整除分块减少循环中乘法的使用,对代码速度可能有一定的提升。

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1.5e6+10;
int mod,T;
bitset<MAXN+1>vis;
int p[MAXN+1],cnt,mu[MAXN+1],N;
inline int Mod(long long a, int pp){return a>=pp ? a%pp : a>=0 ? a : a+pp;}
inline int add(int x,int y){return Mod( (1ll+x+y+mod-1ll),mod);}
inline int mul(int x,int y){return Mod(1ll*x*y,mod);}
inline int qpow(int a,int b){
if(!b)return 1;
if(a<=1||b==1)return a;
a=Mod(a,mod);
int res=1;
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);b>>=1;
}
return res;
}
inline int calc(int x,int y){
if(y==1)return x;
int res=calc(x,y>>1);
res=add(res,mul(res,qpow(x,y>>1)));
if(y&1)res=add(res,mul(x,qpow(x,y-1)));
return res;
}
inline int Calc(int x,int y){int ans=calc(x,y);return mul(ans,ans);}
int ssolve(int n,int d){
int res=0;
for(register int l=1,r;l<=n;l=r+1){
r=(n/(n/l));
int D=n/l;
for(int i=l;i<=r;++i){
if(!mu[i])continue;
res=add(res,mul(mu[i],Calc(qpow(d,i),D)));
}
}
return res;
}
int solve(int n){
int ans=0;
for(register int l=1,r;l<=n;l=r+1){
r=(n/(n/l));
int D=n/l;
for(int i=l;i<=r;++i)ans=add(ans,ssolve(D,qpow(i,i)));
}
return ans;
}
int main(){
scanf("%d",&T);
mu[1]=1;
for(register int i=2;i<=MAXN;++i){
if(!vis[i])p[++cnt]=i,mu[i]=-1;
for(register int j=1;j<=cnt&&i*p[j]<=MAXN;++j){
vis[i*p[j]]=1;
if(Mod(i,p[j])==0)break;
mu[i*p[j]]=-mu[i];
}
}
for(;T;T--){
scanf("%d%d",&N,&mod);
printf("%d\n",solve(N));
}
return 0;
}

经由大佬 @C3H5ClO 大佬证明,上面这份代码实际上是\(O(n\log n)\)的。

这里借用一下 @C3H5ClO 大佬的证明:

\[f(n)=\sum_{d=1}^n\sum_{e=1}^{\lfloor \frac{n}{d} \rfloor}\mu(e)(\sum_{i=1}^{\lfloor \frac{n}{de}\rfloor}d^{de})^2
\]
\[T(n)=O(\sum_{d=1}^n\sum_{e=1}^{\lfloor \frac{n}{d} \rfloor}\log\lfloor \frac{n}{de}\rfloor)
\]
\[T(n)=O(\sum_{i=1}^n\int_0^{\frac{n}{i}}\log\frac{n}{ix}\mathrm{d}x)
\]
\[\int\log\frac{n}{x}\mathrm{d}x=(\log n+1)x-x\log x+C
\]
\[\int_0^n\log\frac{n}{x}\mathrm{d}x=n
\]
\[T(n)=O(\sum_{i=1}^n\frac{n}{i})=O(n\ln n)
\]

(蒟蒻不会微积分惨被教育.jpg)

出这题的本意其实是想看看有没有吊打\(\text{std}\)的做法的,笔者推了很久并没有找到线性的做法。

【题解】 [EZEC-4]求和的更多相关文章

  1. 题解 P1630 【求和】

    题目 发现题解都不够优雅,就自己来一篇 ( 以下除[代码]处代码,其余均为现场手打,如有误请与本蒟蒻联系 ) [分析] 首先,看清楚了,题目是 \(\sum_{i=1}^ai^b\) 的余数 ,而不是 ...

  2. [题解] [CQOI2007] 余数求和

    题面 题解 考虑到这个等式\(a\bmod b = a - b * \lfloor\frac{a}{b}\rfloor\) 所以我们可以得到: \[ \begin{aligned} ans & ...

  3. BestCoder Round #86 部分题解

    Price List 题意: 有n件商品,每天只能买一件,并且会记录账本,问有多少次一定记多了? 题解: 就是求和,最后如果大于和就输出1,否则0. 代码: #include <bits/std ...

  4. [CSP-S模拟测试96]题解

    以后不能再借没改完题的理由不写题解了…… A.求和 求$\sum \sum i+j-1$ 柿子就不化了吧……这年头pj都不考这么弱智的公式化简了…… 坑点1:模数不定,可能没有2的逆元,那么只要先把乘 ...

  5. E题 - A+B for Input-Output Practice (IV)

      Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u   Description You ...

  6. 【洛谷P1403】约数研究

    题目大意:求\[\sum\limits_{i=1}^n\sum\limits_{d|i}1\] 题解:交换求和顺序即可. \[\sum\limits_{i=1}^n\sum\limits_{d|i}1 ...

  7. ACM-ICPC 2018 焦作赛区网络预赛 K题 Transport Ship

    There are NN different kinds of transport ships on the port. The i^{th}ith kind of ship can carry th ...

  8. 【noip】noip201503求和(题解可能不完美,但绝对详细)

    3. 求和 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 题目描述   一条狭长的纸带被均匀划分出了n个格子,格子编号从1到n.每个格子 ...

  9. 【题解】P4091 [HEOI2016/TJOI2016]求和

    [题解]P4091 [HEOI2016/TJOI2016]求和 [P4091 HEOI2016/TJOI2016]求和 可以知道\(i,j\)从\(0\)开始是可以的,因为这个时候等于\(0\).这种 ...

随机推荐

  1. Android开发之 当前日期String类型转date类型 java代码中实现方法

    /** * 获取当前时间 * * @return */ public Date getDate(String str) { try { java.text.SimpleDateFormat forma ...

  2. 【python】装饰器听了N次也没印象,读完这篇你就懂了

    装饰器其实一直是我的一个"老大难".这个知识点就放在那,但是拖延症... 其实在平常写写脚本的过程中,这个知识点你可能用到不多 但在面试的时候,这可是一个高频问题. 一.什么是装饰 ...

  3. Ignatius and the Princess IV (水题)

    "OK, you are not too bad, em... But you can never pass the next test." feng5166 says.  &qu ...

  4. String.format与搭配转化符的使用

    String的format语法搭配转化符,在格式化输出方面效果特别好,值得掌握. 例程: System.out.println("----C1---|----C2---|----C3---| ...

  5. 区块链Fabric 交易流程

    1. 提交交易预案 1)应用端首先构建交易的预案,预案的作用是调用通道中的链码来读取或者写入账本的数据.应用端使用 Fabric 的 SDK 打包交易预案,并使用用户的私钥对预案进行签名. 应用打包完 ...

  6. Netty内置的编解码器和ChannelHandler

    Netty 为许多通用协议提供了编解码器和处理器,几乎可以开箱即用,这减少了你在那些相当繁琐的事务上本来会花费的时间与精力. 通过SSL/TLS 保护Netty 应用程序 SSL和TLS这样的安全协议 ...

  7. java线程的3种实现方式及线程池

    1 准备数据 1.1 目标 为了形象地演示线程的工作现象, 准备两个文件datas/odds.txt和datas/evens.txt, 分别存储奇数和偶数, 内容如下: odds.txt 1 3 5 ...

  8. 分布式处理框架Hadoop的安装与使用

    Hadoop简介 Hadoop是一个由Apache基金会所开发的分布式系统基础架构.用户可以在不了解分布式底层细节的情况下,开发分布式程序. 充分利用集群的威力进行高速运算和存储.Hadoop实现了一 ...

  9. 不定方程(Exgcd)

    #include<cstdio> using namespace std; int x,y; inline int abs(int a){return a>?a:-a;} int e ...

  10. python里面的project、package、module分别是什么

    2020/5/25 1.project(项目) project 即项目,是一个很大的文件夹,里面有好多的 .py 文件. 在Spyder 中点击菜单栏 projects ----->  new ...