您的位置:首页 > 其它

【莫比乌斯反演】关于Mobius反演与gcd的一些关系与问题简化(bzoj 2301 Problem b&&bzoj 2820 YY的GCD&&BZOJ 3529 数表)

2015-07-02 14:44 429 查看
  首先我们来看一道题

  BZOJ 2301 Problem b

Description

  对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

Input

  第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

Output

  共n行,每行一个整数表示满足要求的数对(x,y)的个数

Sample Input

  2

  2 5 1 5 1

  1 5 1 5 2

Sample Output

  14

  3

HINT

  100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000。

  乍一看,大家的force想法:枚举x,y!之后辗转相除!!

  但是复杂度已经爆炸。几乎是一个O(n^3)规模的算法

  

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

#define maxq 40001

#define maxn 100001

using namespace std;

struct ed{
int a,n,m,id,ans;
}a[maxq];

bool is_prime[maxn];

int prime[maxn],b=0,mu[maxn],bit[maxn],ans[maxn];

struct sb{
int num,Id;
}f[maxn];

void mu_choice()
{
mu[1]=1;
for(int i=2;i<=maxn-1;i++)
{
if(!is_prime[i])prime[++b]=i,mu[i]=-1;
int j=1,t=2*i;
while(j<=b&&t<=maxn-1)
{
is_prime[t]=1;
if(i%prime[j]==0)
{
mu[t]=0;
break;
}
mu[t]=-mu[i];
t=prime[++j]*i;
}
}
for(int i=1;i<maxn;i++)
{
for(int j=1;j*i<maxn;j++)
f[j*i].num+=i;
f[i].Id=i;
}
}

bool cmp(const ed A,const ed B)
{
return A.a<B.a;
}

bool cmp2(const sb A,const sb B)
{
return A.num<B.num;
}

void add(int pos,int num)
{
while(pos<=maxn-1)
{
bit[pos]+=num;
pos+=pos&-pos;
}
}

int sum(int pos)
{
int ne=0;
while(pos>0)
{
ne+=bit[pos];
pos-=pos&-pos;
}
return ne;
}

void solve(int x)
{
int last;
for(int i=1;i<=a[x].n;i=last+1)
{
last=min(a[x].n/(a[x].n/i),a[x].m/(a[x].m/i));
ans[a[x].id]+=(sum(last)-sum(i-1))*(a[x].n/i)*(a[x].m/i);
}
}

int main()
{
#ifndef ONLINE_JUDGE
freopen("3529.in","r",stdin);
freopen("3529.out","w",stdout);
#endif
int T,aa,n,m;
scanf("%d",&T);
for(int i=1;i<=T;i++)
{
scanf("%d%d%d",&n,&m,&aa);
if(n>m)swap(n,m);
a[i].a=aa,a[i].n=n,a[i].m=m,a[i].id=i;
}
mu_choice();
sort(1+a,a+1+T,cmp);
sort(1+f,f+maxn,cmp2);
int puck=1;
for(int i=1;i<=T;i++)
{
while(puck<maxn&&f[puck].num<=a[i].a)
{
for(int j=1;j<=((maxn-1)/f[puck].Id);j++)
add(j*f[puck].Id,mu[j]*f[puck].num);
puck++;
}
solve(i);
}
for(int i=1;i<=T;i++)
printf("%d\n",ans[i]&0x7fffffff);
return 0;
}


View Code

  代码凑合着看吧。。  

  

  

  

  





内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: