[bzoj2301][HAOI2011]Problem b

[bzoj2301][HAOI2011]Problem b

标签: 莫比乌斯反演 分块


题目链接

题解

$x\in[1,a],y\in[1,b] $的情况更方便处理。
那么只需要做一个容斥原理就行了。
另外注意这道题O(nk)是不能过的。
所以需要数论分块一下。

Code


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
	int sum=0,p=1;char ch=getchar();
	while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
	if(ch=='-')p=-1,ch=getchar();
	while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
	return sum*p;
}

int a,b,c,d,k;

const int maxn=1e5+20;

int prime[maxn],mark[maxn],tot,mu[maxn],s[maxn];

void prepare()
{
	mu[1]=1;
	s[1]=1;
	REP(i,2,50000)
	{
		if(!mark[i])
		{
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=tot && prime[j]*i<=50000;j++)
		{
			mark[i*prime[j]]=1;
			if(i%prime[j])mu[i*prime[j]]=-mu[i];
			else {mu[i*prime[j]]=0;break;}
		}
		s[i]=s[i-1]+mu[i];
	}
}

void init()
{
	a=read();b=read();c=read();d=read();k=read();
}

ll js(int x,int y)
{
	ll ans=0;
	if(x<y)swap(x,y);
	x/=k;y/=k;
	//for(int d=k;d<=y;d+=k)ans+=(ll)mu[d/k]*(x/d)*(y/d);
	int nxt1,nxt2,nxt;
	for(int i=1;i<=y;i=nxt)
	{
		nxt1=x/(x/i);nxt2=y/(y/i);
		nxt=min(nxt1,nxt2);
		ans+=(ll)(s[nxt]-s[i-1])*(x/i)*(y/i);
		nxt++;
	}
	return ans;
}
	
void doing()
{
	printf("%lld\n",js(b,d)-js(a-1,d)-js(b,c-1)+js(a-1,c-1));
}

int main()
{
	freopen("GCD.in","r",stdin);
	freopen("GCD.out","w",stdout);
	prepare();
	int t=read();
	while(t--)
	{
		init();
		doing();
	}
	return 0;
}

posted @ 2017-10-20 22:30  Deadecho  阅读(111)  评论(2编辑  收藏  举报