您的位置:首页 > 其它

【莫比乌斯反演+容斥】BZOJ2301-[HAOI2011]Problem b(成为权限狗的第一题纪念!)

2016-07-27 15:23 92 查看
【题目大意】

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

【思路】

“怎么又是你系列……”思路和分块方法分别参见:🐈🐩 ←岛国输入法超级好用啊wwww

最后容斥一下:ans=g(b,d,k)−g(a−1,d,k)−g(b,c−1,k)+g(a−1,c−1,k)

【错误点】

我干了件很愚蠢的事,一上来就把a,b,c,d全部除以k,再按上述容斥的方式传入了子函数。注意,是(a-1)/k,不是a/k-1。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=50000+50;
const int INF=0x7fffffff;
int a,b,c,d,k;
int miu[MAXN],prime[MAXN],pnum;
ll miusum[MAXN];

void getmiu(int maxn)
{
memset(miusum,0,sizeof(miusum));
miu[1]=miusum[1]=1;
for (int i=2;i<maxn;i++) miu[i]=-INF;
for (int i=2;i<maxn;i++)
{
if (miu[i]==-INF)
{
miu[i]=-1;
prime[++pnum]=i;
}
for (int j=1;j<=pnum;j++)
{
if (i*prime[j]>=maxn) break;
if (i%prime[j]==0) miu[i*prime[j]]=0;
else miu[i*prime[j]]=-miu[i];

}
miusum[i]=miusum[i-1]+miu[i];
}
}

ll solve(int b,int d,int k)
{
b/=k;d/=k;
int ub=min(b,d),pos;
ll ret=0;
for (int i=1;i<=ub;i=pos+1)
{
pos=min(b/(b/i),d/(d/i));
ret+=(ll)(miusum[pos]-miusum[i-1])*(ll)(b/i)*(ll)(d/i);
}
return ret;
}

int main()
{
int T;
getmiu(MAXN-1);
scanf("%d",&T);
while (T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
ll ans=solve(b,d,k)-solve(a-1,d,k)-solve(c-1,b,k)+solve(a-1,c-1,k);
printf("%lld\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: