BZOJ 2301 problem b

Posted on 2016-01-29 21:19  ziliuziliu  阅读(190)  评论(0编辑  收藏  举报

 容斥+莫比乌斯反演+分块大法。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
long long miu[50005];
long long a,b,c,d,k,t;
long long prime[50005],cnt=0,pre[50005];
bool vis[50005];
void make_table()
{
miu[1]=1;
for (int i=2;i<=50000;i++)
{
if (vis[i]==false)
{
prime[++cnt]=i;
miu[i]=-1;
}
for (int j=1;j<=cnt && prime[j]*i<=50000;j++)
{
vis[i*prime[j]]=true;
if (i%prime[j]==0)
{
miu[i*prime[j]]=0;
break;
}
else
miu[i*prime[j]]=-miu[i];
}
}
for (int i=1;i<=50000;i++)
pre[i]=pre[i-1]+miu[i];
}
long long work(long long n,long long m,long long k)
{
if (n>m) swap(n,m);
long long i=1,ans=0;
while (i<=(n/k))
{
long long j;
if ((n/(k*i)==0) || (m/(k*i)==0)) j=0;
else j=min(((n/k)/((n/k)/i)),((m/k)/((m/k)/i)));
ans=ans+(pre[j]-pre[i-1])*((n/k)/i)*((m/k)/i);
i=j+1;
}
return ans;
}
int main()
{
memset(vis,false,sizeof(vis));
memset(pre,0,sizeof(pre));
scanf("%lld",&t);
make_table();
for (int i=1;i<=t;i++)
{
scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
printf("%lld\n",work(b,d,k)-work(a-1,d,k)-work(b,c-1,k)+work(a-1,c-1,k));
}
return 0;
}