【数論】モビウスの反転例題のまとめ
9003 ワード
指路ブログ:peng-ymモビウス反転
・(d=1)の場合、(mu(d)=1);・(d=prod_{i=1}^k p_i)かつ(p_i)が相互異素数である場合、(mu(d)=(-1)^k).(d)が任意の質量因子を含むべき乗が2以上である場合、関数値は0になります.・任意の正の整数(n)、(sum_{d|n}^{}mu(d)=[n=1])について.・任意の正の整数(n)、(sum_{d|n}^{}{frac{mu(d)}d}={frac{phi(n)}n})について.・線ふるいモビウス関数(順帯オーラ関数:
・F(n)とf(n)は非負の整数集合に定義された2つの関数であり、条件を満たす[F(n)=sum_{d|n}f(d)]では、[f(n)=sum_{d|n}μ(d)F(lfloorfrac ndrfloor)]この定理をモビウス反転定理と呼ぶ.モビウスの反転には別の形式があり,F(n)とf(n)が[F(n)=sum_{n|d}f(d)]を満たすと[f(n)=sum_{n|d}を押し出すことができる.μ(\frac dn)F(d)\]
例題
luoguP 2257 YYのGCD題目説明:与えられたN,M,1<=x<=N,1<=y<=M,gcd(x,y)が質量数である(x,y)の 対を求める入力フォーマット:第1行の1つの整数Tはデータ群数の次のT行を表し、各行の2つの正の整数はNを表し、M を表す.データ範囲:T=10000;N, M <= 10000000 出力フォーマット:T行、各行に1つの整数 指路ブログ:peng-ym YYのGCD等価:(Ans=sum_{i=1}^nsum_{j=1}^m[gcd(x,y)=prim]) (f(d))を(gcd(i,j)=d)の個数、(F(n))を(gcd(i,j)=n)と(n)の倍数の個数、すなわち、[f(d)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d][F(n)=sum_{n|d}f(d)=lfloorfrac Nnrfloorlflflloorlfllorlfllorlfllorlfllorlflloor oorfrac Mnrfloor]モビウスにより反転[f(n)=sum_{n|d}mu(lfloorfrac dnrfloor)F(d)] 簡略化式:[Ans=sum_{pin prim}sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=p]]を(f(p))に代入する[begin{align*} Ans&=sum_{pin prim}f(p)\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\{align*}]列挙項目を変更します.列挙(lfloorfracdprfloor):[begin{align*} Ans&=sum_{pin prim}sum_{d=1}^{min(lfloorfracnprfloor,lfloorfracmp rfloor)}mu(d)F(dp)\\\\&=sum_{pin prim}sum_{d=1}^{min(lfloorfracnprfloor,lfloorfloorfloorfracnpfloor\\\\\floor\\\\\\\fracmprfloor)}mu(d)lfloorfrac nprfloorlfloorfrac mprfloorend{align*}]dpをT:[begin{align*}Ans&=sum_{T=1}^{min(n,m)}sum_{t|T,tin prim}mu(\lfloor\frac Tt\rfloor)\lfloor\frac nT\rfloor\lfloor\frac mT\rfloor\\& =\sum_{T=1}^{min(n,m)}\lfloor\frac nT\rfloor\lfloor\frac mT\rfloor(\sum_{t|T,t\in prim}\mu(\lfloor\frac Tt\rfloor)\;)\end{align*}\] 以降ブロック を除去する.コード: luoguP3455 ZAP-Queries 題目説明:a,b,dを与えて、1<=x<=aを求めて、1<=y<=bでgcd(x,y)=dの(x,y)はどれだけの対 があります入力フォーマット:第1行の1つの整数Tはデータ群数の次のT行を表し、各行の3つの正の整数はa,b,d を表す.データ範囲(1leq Tleq 5times 10^4,1leq dleq a,bleq 5times 10^4) 出力フォーマット:T行、各行に1つの整数 指路ブログ:peng-ym ZAP-Queries等価:(Ans=sum_{i=1}^asum_{j=1}^b[gcd(x,y)=d]) (f(d))を(gcd(i,j)=d)の個数とし、(F(n))を(gcd(i,j)=n)と(n)の倍数の個数とする.すなわち、[f(d)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d][F(n)=sum_{n|d}f(d)=lfloorfracanfracanrfloorlflooo rlflooo rlflooo o o rlfloorlfloorlflooo o o rlfloorlfloorflrfrac bnrfloor]モビウスより反転:[f(n)=sum_{n|d}mu(lfloorfrac dnrfloor)F(d)]混同しないように題意のdをnに置き換え、(f(n))を代入する:[begin{align*} Ans&=f(n)\&=sum_{n|d}mu(lfloorfracdn rfloor)F(d)end{ align*}]列挙項を交換し、列挙(lfloorfracdn rfloor)を(t):[Ans=sum_{t=1}^{min(lfloorfracapfloorfracaploor,lfloorfloorfloorfloorfloorfloorfloorfloorfloorfloorfloorfloor\frac bdrfloor}mu(t)lfloorfrac a{td}rfloorlfloorfrac b{td}rfloor] 以降ブロック を除去する.コード: luoguP 3327月数個と題目説明:d(x)をxの約数とし、n,mを与え、[sum_{i=1}^nsum_{j=1}^m d(ij)] を求める入力フォーマット:最初の行の1つの整数Tはデータグループ数の次のT行を表し、各行の2つの正の整数n,m データ範囲(1leq T,n,mleq 5times 10^4) 出力フォーマット:T行、各行に1つの整数 指路ブログ:peng-ym約数と重要性:[d(ij)=sum_{x|i}sum_{y|i}[gcd(x,y)=1]] 等価(Ans=sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|i}[gcd(x,y)=1]) (f(d))を(gcd(i,j)=d)の個数、(F(n))を(gcd(i,j)=n)と(n)の倍数の個数、すなわち、[f(d)=sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d][F(n)=sum_{n|d}f(d)=lfloorfrac Nnrfloorlflflloorlfllorlfllorlfllorlfllorlflloor oorfrac Mnrfloor]モビウスにより反転[f(n)=sum_{n|d}mu(lfloorfrac dnrfloor)F(d)] で[begin{align*}Ans&=sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|i}[gcd(x,y)=1]\&=sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|i}\sum_{d|gcd(x,y)}\mu(d)\\&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|i}\sum_{d=1}^{min(n,m)}\mu(d)*[d|gcd(x,y)]\;\;\;(改列挙d)\&=sum_{d=1}^{min(n,m)}\mu(d)\sum_{i=1}^n\sum_{j=1}^m\sum_{x|i}\sum_{y|i}[d|gcd(x,y)]\;\;\;(mu(d)を抽出)\end{align*}]は、列挙i,jおよびそれらの約数から列挙の約数に変更され、これらの約数の倍数の個数に直接乗じられる.各約数はその倍数に寄与するから:[begin{align*}Ans&=sum_{d=1}^{min(n,m)}mu(d)sum_{x=1}^nsum_{y=1}^m[d|gcd(x,y)]lfloorfrac nxrfloorlfloorfrac myrfloor&=sum_{d=1}^{min(n,m)}\mu(d)\sum_{x=1}^{\lfloor\frac nd\rfloor}\sum_{y=1}^{\lfloor\frac md\rfloor}\lfloor\frac n{dx}\rfloor\lfloor\frac m{dy}\rfloor\;\;\;(列挙x,yを列挙dx,dyに変更)&=sum_{d=1}^{min(n,m)}\mu(d)(\sum_{x=1}^{\lfloor\frac nd\rfloor}\lfloor\frac n{dx}\rfloor)(\sum_{y=1}^{\lfloor\frac md\rfloor}\lfloor\frac m{dy}\rfloor)\;\;\;(lfloorfrac n{dx}rfloorはyに関係ないので繰り上げ可能)\end{align*}] 以降ブロック を除去する.コード:
モビウス関数:
・(d=1)の場合、(mu(d)=1);・(d=prod_{i=1}^k p_i)かつ(p_i)が相互異素数である場合、(mu(d)=(-1)^k).(d)が任意の質量因子を含むべき乗が2以上である場合、関数値は0になります.・任意の正の整数(n)、(sum_{d|n}^{}mu(d)=[n=1])について.・任意の正の整数(n)、(sum_{d|n}^{}{frac{mu(d)}d}={frac{phi(n)}n})について.・線ふるいモビウス関数(順帯オーラ関数:
int pri[maxn+5],mu[maxn+5],phi[maxn];
void init()
{
mu[1]=phi[1]=1;
for(int i=2;i
モビウス
・F(n)とf(n)は非負の整数集合に定義された2つの関数であり、条件を満たす[F(n)=sum_{d|n}f(d)]では、[f(n)=sum_{d|n}μ(d)F(lfloorfrac ndrfloor)]この定理をモビウス反転定理と呼ぶ.モビウスの反転には別の形式があり,F(n)とf(n)が[F(n)=sum_{n|d}f(d)]を満たすと[f(n)=sum_{n|d}を押し出すことができる.μ(\frac dn)F(d)\]
例題
luoguP 2257 YYのGCD
#include
#define debug1 printf("!");
#define debug2 puts("#");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=1e7;
const int mod=6893911;
const int inf=0x3f3f3f3f;
templateinline void read(T&x)
{
char c;
while(!isdigit(c=getchar()));x=c-'0';
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-'0';
}
ll sum[maxn+5];
int mu_pfac[maxn+5];
int mu[maxn+5];
int pri[maxn+5],cnt;
inline void init()
{
mu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!pri[i])
{
pri[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*pri[j]<=maxn;j++)
{
pri[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=maxn;i++)
for(int j=1;j<=cnt&&i*pri[j]<=maxn;j++)
mu_pfac[i*pri[j]]+=mu[i];
for(int i=1;i<=maxn;i++)
sum[i]=sum[i-1]+(ll)mu_pfac[i];
}
inline ll solve(int n,int m)
{
if(n>m)swap(n,m);
ll ans=0;
for(int l=1,r;l<=n;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
return ans;
}
int main()
{
init();
int T;
read(T);
while(T--)
{
int n,m;
read(n);read(m);
printf("%lld
",solve(n,m));
}
}
#include
#define debug1 printf("!");
#define debug2 puts("#");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=1e5+5;
const int mod=6893911;
const int inf=0x3f3f3f3f;
templateinline void read(T&x)
{
char c;
while(!isdigit(c=getchar()));x=c-'0';
while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-'0';
}
ll smu[maxn+5];
int mu[maxn+5];
int pri[maxn+5],cnt;
inline void init()
{
mu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!pri[i])
{
pri[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*pri[j]<=maxn;j++)
{
pri[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<=maxn;i++)smu[i]=smu[i-1]+(ll)mu[i];
}
inline ll solve(int a,int b,int d)
{
if(a>b)swap(a,b);
ll ans=0;
for(int l=1,r;l<=a;l=r+1)
{
r=min(a/(a/l),b/(b/l));
ans+=1ll*(a/(l*d))*(b/(l*d))*(smu[r]-smu[l-1]);
}
return ans;
}
int main()
{
init();
int T;
read(T);
while(T--)
{
int a,b,d;
read(a);read(b);read(d);
printf("%lld
",solve(a,b,d));
}
}
#include
#define debug printf("#");
#define pb push_back
using namespace std;
typedef long long ll;
const int mod=998244353;
const int maxn=5e4+5;
const int inf=0x3f3f3f3f;
ll s[maxn];
//ll phi[maxn+5];
int mu[maxn+5];
int pri[maxn],p=0;
bool isp[maxn+5]={0};
inline void init()
{
// phi[1]=1;
mu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!isp[i])
{
pri[++p]=i;
// phi[i]=i-1;
mu[i]=-1;
}
for(int j=1;j<=p&&i*pri[j]<=maxn;j++)
{
isp[i*pri[j]]=1;
if(i%pri[j]==0)
{
// phi[i*pri[j]]=phi[i]*pri[j];
break;
}
// phi[i*pri[j]]=phi[i]*(pri[j]-1);
mu[i*pri[j]]=-mu[i];
}
}
for(int i=2;i<=maxn;i++)
{
// phi[i]+=phi[i-1];
mu[i]+=mu[i-1];
}
for(int i=1;i<=50000;i++)
{
for(int l=1,r;l<=i;l=r+1)
{
r=i/(i/l);
s[i]+=(r-l+1)*(i/l);
}
}
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
int n,m,up;
ll ans=0;
scanf("%d%d",&n,&m);
up=min(n,m);
for(ll l=1,r;l<=up;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=1ll*(mu[r]-mu[l-1])*s[n/l]*s[m/l];
}
printf("%lld
",ans);
}
}