bzoj2301: [HAOI2011]Problem b:https://www.lydsy.com/JudgeOnline/problem.php?id=2301
一看题目 模板题
模板题:caioj1280: [视频]【莫比乌斯反演模板题】GCD http://caioj.cn/problem.php?id=1280
证明:https://blog.csdn.net/herodeathes/article/details/77932208
因为不保证a,c=1 减掉1~a和1~d 1~c和1~b 的匹配 然后把重复的1~a和1~c的匹配加回来
然后就T掉了nice!
加一个分块加速
因为有很大一段的(b/i) (d/i) 是一样的
就相当于乘法分配率
U[ ]用上前缀和之后 直接瞎跳小的那个就ok
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int prime[51000],mu[51000],pr;//mu:反演时的系数(容斥)
bool v[110000];
void get_mu()
{
memset(v,1,sizeof(v));
mu[1]=1;mu[0]=0;
for (int i=2;i<=50000;i++)
{
if (v[i]==true)
{
prime[++pr]=i;
mu[i]=-1;//1个也是奇数个
}
for(int j=1;j<=pr&&prime[j]*i<=50000;j++)
{
v[prime[j]*i]=0;
if (i%prime[j]==0)
{
mu[i*prime[j]]=0; //i包含了prime[j] e>1
break;
}
else
{
mu[i*prime[j]]=-mu[i];//奇变偶 偶变奇
}
}
mu[i]+=mu[i-1];//前缀和
}
}
long long get(int a,int b)
{
long long ans=0;
int next=0;
int c=min(a,b);
for (int i=1;i<=c;i=next+1)
{
next=min(a/(a/i),b/(b/i));
ans+=(long long)(mu[next]-mu[i-1])*(a/i)*(b/i);
}
return ans;
}
int main()
{
//F(t)=gcd(x,y)%t==0 的x,y个数 =gcd(x,y) 的倍数的个数 F(6)=f(1)+f(2)+f(3)+f(6);
//f(t)=gcd(x,y)=t 的x,y个数 = t的gcd个数 此时由f(t) 推回F(t) 这就是反演公式 F(t)=(b/t)*(b/t)
//如果gcd(x,y)=1 gcd(x*k,,y*k)=k 直接除掉 k 然后求 f(1) 然后 x,y在1~b选的时候可能会有重(gcd(2,3)=gcd(3,2)) /2去重
get_mu();
int t;
scanf("%d",&t);
while (t--)
{
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if (k==0) {printf("0\n");continue;}
a=(a-1)/k;b/=k;c=(c-1)/k;d/=k;k=1;
long long ans1=0,ans2=0,ans3=0,ans4=0,ans5=0;
ans1=get(b,d);
ans3=get(a,d);//1~a 和 1~d 匹配
ans4=get(c,b);//1~c 和 1~b 匹配
ans5=get(a,c);//1~a 和 1~c 匹配
printf("%lld\n",ans1-ans3-ans4+ans5);
}
return 0;
}