您的位置:首页 > 其它

bzoj2154: Crash的数字表格/2693: jzptab [莫比乌斯反演、数论推导]

2014-10-03 10:10 483 查看
公式编辑器不会用,只能从认识的神犇空间里copy一下。



考虑求解:





那么



再来考虑求最终答案:



事实上到了这一步之后就可以求解2154了,在求F(n,m)中分块,在求Ans(n,m)中也分块处理,这样的时间复杂度是O(sqrt(n)*sqrt(n))=O(n),用线性筛法求u(d)d^2(u(d)表示莫比乌斯函数),总复杂度仍然是O(n),但是这样没法做到快速支持多组查询,所以还要继续化简:



然后我们惊奇的发现H(D)是可以用线性筛顺便求出,那么对D分块,处理出一个H(D)的前缀和,这样就可以在O(sqrt(n))的时间内处理出一个询问了,所以总复杂度是O(n)-O(sqrt(n)),这样就可以解决2693啦。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

看完后的感受:



个人觉得这才是莫比乌斯反演的精髓所在,G(n,m,d)是什么并不重要,它依不同题目变化不同,但是F(n,m)这样的反演求法,可以保证i,j互质。

很多和gcd和lcm有关的题目都可以转化为这样的模型。

其余部分,都是些无关莫比乌斯反演的数论推导,倒是没有那么难理解。

我们要做的,就是找到一个奇怪的像H一样的积性函数,并在欧拉筛中对其进行预处理。

2154

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#define For(i,l,r) for(ll (i)=(l);(i)<=(r);(i)++)
using namespace std;

typedef long long ll;

const ll N=10100000;
const ll T=2;
const ll MOD=20101009;

ll pr
,H
,A[T][2],P
,tot=0,lim=0;
bool np
;

void Pre(){
memset(np,0,sizeof(np));
H[1]=1; np[1]=1;
For(i,2,lim){
if(!np[i]){
H[i]=(MOD-(((ll)i*i)%MOD)+i)%MOD;
pr[++tot]=i;
}for(ll j=1;j<=tot&&i*pr[j]<=lim;j++){
np[i*pr[j]]=1;
if(i%pr[j]==0){
H[i*pr[j]]=(ll)pr[j]*H[i]%MOD;
break;
}else H[i*pr[j]]=(ll)H[i]*H[pr[j]]%MOD;
}
}P[0]=0; For(i,1,lim){
P[i]=(P[i-1]+H[i])%MOD;
}
}

inline ll S( ll n , ll m ) {
return ((n*(n+1)/ll(2))%MOD)*((m*(m+1)/ll(2))%MOD)%MOD;
}
inline ll solve( ll n , ll m ) {
ll ans=0,pos,v;
if (n>m) swap(n,m) ;
for(ll i=1;i<=n;i=pos+1){
pos=min(n/(n/i),m/(m/i));
v=((P[pos]-P[i-1]+MOD)%MOD*S(n/i,m/i))
4000
%MOD;
(ans+=v)%=MOD;
}return ll(ans) ;
}

int main(){
int t=1;
For(i,1,t){
scanf("%lld%lld",&A[i][0],&A[i][1]);
lim=max(lim,max(A[i][0],A[i][1]));
}Pre();
For(i,1,t) printf("%lld\n",solve(A[i][0],A[i][1])%MOD);
return 0;
}

2693

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#define For(i,l,r) for(ll (i)=(l);(i)<=(r);(i)++)
using namespace std;

typedef long long ll;

const ll N=10100000;
const ll T=10010;
const ll MOD=100000009;

ll pr
,H
,A[T][2],P
,tot=0,lim=0;
bool np
;

void Pre(){
memset(np,0,sizeof(np));
H[1]=1; np[1]=1;
For(i,2,lim){
if(!np[i]){
H[i]=(MOD-(((ll)i*i)%MOD)+i)%MOD;
pr[++tot]=i;
}for(ll j=1;j<=tot&&i*pr[j]<=lim;j++){
np[i*pr[j]]=1;
if(i%pr[j]==0){
H[i*pr[j]]=(ll)pr[j]*H[i]%MOD;
break;
}else H[i*pr[j]]=(ll)H[i]*H[pr[j]]%MOD;
}
}P[0]=0; For(i,1,lim){
P[i]=(P[i-1]+H[i])%MOD;
}
}

inline ll S( ll n , ll m ) {
return ((n*(n+1)/ll(2))%MOD)*((m*(m+1)/ll(2))%MOD)%MOD;
}
inline ll solve( ll n , ll m ) {
ll ans=0,pos,v;
if (n>m) swap(n,m);
for(ll i=1;i<=n;i=pos+1){
pos=min(n/(n/i),m/(m/i));
v=((P[pos]-P[i-1]+MOD)%MOD*S(n/i,m/i))%MOD;
(ans+=v)%=MOD;
}return ll(ans) ;
}

int main(){
int t;
scanf("%d",&t);
For(i,1,t){
scanf("%lld%lld",&A[i][0],&A[i][1]);
lim=max(lim,max(A[i][0],A[i][1]));
}Pre();
For(i,1,t) printf("%lld\n",solve(A[i][0],A[i][1])%MOD);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: