码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2301 HAOI2011 Problem b 容斥原理+莫比乌斯反演

时间:2014-12-16 11:44:43      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj2301   容斥原理   莫比乌斯反演   

题目大意:多次询问有多少个数对(x,y)满足a<=x<=b,c<=y<=d,且GCD(x,y)=k

首先利用容斥原理将询问分解 问题转化为求有多少个数对(x,y)满足x<=m,y<=n,且GCD(x,y)=k

这里就可以利用到莫比乌斯反演:

bubuko.com,布布扣

我们令F(d)为GCD(x,y)=d且x<=m,y<=n的数对数

f(d)为d|GCD(x,y)且x<=m,y<=n的数对数

那么显然有F(d)=(n/d)*(m/d)

但是直接套用公式还是O(n^2)级别的

考虑到(n/d)*(m/d)最多只会有2√n个商 因此我们可以枚举这个商 对μ维护一个前缀和来计算

具体实现详见代码

曾经看了某人的题解天真地认为暴力可以过于是兴冲冲地写了暴力去交了一发50s的TLE……

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
typedef long long ll;
ll mu[M],prime[M],tot;
bool not_prime[M];
void Linear_Shaker()
{
	int i,j;
	mu[1]=1;
	for(i=2;i<M;i++)
	{
		if(!not_prime[i])
		{
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(j=1;j<=tot&&i*prime[j]<M;j++)
		{
			not_prime[prime[j]*i]=true;
			if(i%prime[j]==0)
			{
				mu[prime[j]*i]=0;
				break;
			}
			mu[prime[j]*i]=-mu[i];
		}
	}
	for(i=1;i<M;i++)
		mu[i]+=mu[i-1];
}
ll Calculate(int m,int n,int k)
{
	int i,last;
	long long re=0;
	n/=k;m/=k;
	for(i=1;i<=m&&i<=n;i=last+1)
	{
		last=min(n/(n/i),m/(m/i));
		re+=(mu[last]-mu[i-1])*(m/i)*(n/i);
	}
	return re;
}
int main()
{
	int T,a,b,c,d,k;
	Linear_Shaker();
	for(cin>>T;T;T--)
	{
		scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
		printf("%lld\n",	 Calculate(b,d,k)
						-Calculate(a-1,d,k)
						-Calculate(b,c-1,k)
						+Calculate(a-1,c-1,k) );
	}
}


BZOJ 2301 HAOI2011 Problem b 容斥原理+莫比乌斯反演

标签:bzoj   bzoj2301   容斥原理   莫比乌斯反演   

原文地址:http://blog.csdn.net/popoqqq/article/details/41957687

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!