Luogu P3327 [SDOI2015]约数个数和 题解

题目传送门

题目大意

i=1nj=1md(ij)

其中 n,m,T5104,多组测试数据,T 为测试组数。

题目解析

众所周知,考虑莫比乌斯反演的时候,需要出现 gcd,然后枚举 gcd,展开 [x=1]
所以我们考虑咋么出现 gcd
根据 人类智慧,我们可以得到约数函数 d 具有如下性质:

d(ij)=x|iy|j[gcd(x,y)=1]=x|iy|jk|x,k|yμ(k)=k|i,k|jμ(k)k|x,x|ik|y,y|j1=k|i,k|jμ(k)d(ik)d(jk)

这样的好处就是,这里出现了 ik,所以最后我们枚举 ik 的时候,约数函数里面就不会有最外面枚举的 k 了。
然后就是套路了,直接回带。

i=1nj=1md(i,j)=i=1nj=1mk|i,k|jμ(k)d(ik)d(jk)=k=1min{n,m}μ(k)k|i,ink|j,jmd(ik)d(jk)=k=1min{n,m}μ(k)i=1n/kj=1m/kd(i)d(j)=k=1min{n,m}μ(k)S(n/k)S(m/k)

其中

S(n)=i=1nd(i)

线性筛+整除分块,Θ(n+Tn)

其实可以算是多余的代码:

#include<cstdio>
#define db double
#define gc getchar
#define pc putchar
#define U unsigned
#define ll long long
#define ld long double
#define ull unsigned long long
#define Tp template<typename _T>
#define Me(a,b) memset(a,b,sizeof(a))
Tp _T mabs(_T a){ return a>0?a:-a; }
Tp _T mmax(_T a,_T b){ return a>b?a:b; }
Tp _T mmin(_T a,_T b){ return a<b?a:b; }
Tp void mswap(_T &a,_T &b){ _T tmp=a; a=b; b=tmp; return; }
Tp void print(_T x){ if(x<0) pc('-'),x=-x; if(x>9) print(x/10); pc((x%10)+48); return; }
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LL_INF (0x7fffffffffffffff)
#define N 50000
#define maxn 50039
#define maxm
#define MOD
#define Type int
#ifndef ONLINE_JUDGE
//#define debug
#endif
using namespace std;
Type read(){
char c=gc(); Type s=0; int flag=0;
while((c<'0'||c>'9')&&c!='-') c=gc(); if(c=='-') c=gc(),flag=1;
while('0'<=c&&c<='9'){ s=(s<<1)+(s<<3)+(c^48); c=gc(); }
if(flag) return -s; return s;
}
int n,m,isp[maxn],pr[maxn],cnt; ll mu[maxn],d[maxn],g[maxn];
void init(){
int i,j; d[1]=1; mu[1]=1;
for(i=2;i<=N;i++){
if(!isp[i]) pr[++cnt]=i,d[i]=2,mu[i]=-1,g[i]=1;
for(j=1;j<=cnt&&i*pr[j]<=N;j++){
isp[i*pr[j]]=1; mu[i*pr[j]]=-mu[i]; d[i*pr[j]]=d[i]*2; g[i*pr[j]]=1;
if(i%pr[j]==0){ mu[i*pr[j]]=0; g[i*pr[j]]=g[i]+1; d[i*pr[j]]=d[i]/(g[i]+1)*(g[i]+2); break; }
}
}
for(i=1;i<=N;i++) mu[i]+=mu[i-1],d[i]+=d[i-1];
}
void work(){
n=read(); m=read(); int l=1,r; ll ans=0;
while(l<=n&&l<=m){
r=mmin(n/(n/l),m/(m/l));
ans+=1ll*(mu[r]-mu[l-1])*d[n/l]*d[m/l];
l=r+1;
} print(ans),pc('\n');
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
init(); int T=read(); while(T--) work(); return 0;
}
posted @   jiangtaizhe001  阅读(22)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示