苗神:学屁莫比乌斯啊,学了你也不会,那么菜,学什么莫比乌斯。
大菜鸡:???
公式打着太麻烦,就直接贴我自己模板里面的公式了。
证明:是时候给别人贡献一波访问量了(其实是我懒得打证明了)
const int MAXN=50000;
int v[MAXN+10];
int miu[MAXN+10];
int sum[MAXN+10];//求前缀和
void Moblus()
{
for(int i=1;i<=MAXN;i++)
{
miu[i]=1;
v[i]=0;
}
for(int i=2;i<=MAXN;i++)
{
if(v[i])
continue;
miu[i]=-1;
for(int j=2*i;j<=MAXN;j+=i)
{
v[j]=1;
if((j/i)%i==0)
miu[j]=0;
else
miu[j]*=-1;
}
}
/*记录莫比乌斯函数的前缀和
for(int i=1;i<=MAXN;i++)
{
sum[i]=sum[i-1]+miu[i];
}
*/
}
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
第一行包含一个正整数n,表示一共有n组询问。(1<=n<= 50000)接下来n行,每行表示一个询问,每行三个正整数,分别为a,b,d。(1<=d<=a,b<=50000)
对于每组询问,输出到输出文件zap.out一个正整数,表示满足条件的整数对数。
2
4 5 2
6 4 3
3
2
对于第一组询问,满足条件的整数对有(2,2),(2,4),(4,2)。对于第二组询问,满足条件的整数对有(6,3),(3,3)。
RT
看上面那个链接
日常分块,日常int类型转LL然后做乘法。
#include
using namespace std;
typedef long long ll;
const int MAXN=50000;
int v[MAXN+10];
int miu[MAXN+10];
int sum[MAXN+10];
void Moblus()
{
for(int i=1;i<=MAXN;i++)
{
miu[i]=1;
v[i]=0;
}
for(int i=2;i<=MAXN;i++)
{
if(v[i])
continue;
miu[i]=-1;
for(int j=2*i;j<=MAXN;j+=i)
{
v[j]=1;
if((j/i)%i==0)
miu[j]=0;
else
miu[j]*=-1;
}
}
for(int i=1;i<=MAXN;i++)
{
sum[i]=sum[i-1]+miu[i];
}
}
int main()
{
Moblus();
int T;
scanf("%d",&T);
while(T--)
{
int n,m,d;
ll ans=0;
scanf("%d%d%d",&n,&m,&d);
if(n>m)
swap(n,m);
n/=d,m/=d;
for(int i=1,last=1;i<=n;i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=1ll*(sum[last]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",ans);
}
return 0;
}
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
共n行,每行一个整数表示满足要求的数对(x,y)的个数
2
2 5 1 5 1
1 5 1 5 2
14
3
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
RT
容斥。先跟上题一样,求[1,b],[1,d]内满足的答案数,减去[1,a-1],[1,d]和[1,b],[1,c-1]内的答案数,由于[1,a-1],[1,c-1]内的答案数被减了两次,所以我们加一次回去。即可求出[a,b],[c,d]内的答案数。
因为要求的是[a,b],[c,d]内的答案数,所以减掉的是a-1和b-1的答案数,所以需要先a–,c–。
某菜鸡最开始是先a/=k,c/=k然后再a–,c–,遂自闭。
#include
using namespace std;
typedef long long ll;
const int MAXN=60000;
int v[MAXN+10];
int miu[MAXN+10];
int sum[MAXN+10];
void Moblus()
{
for(int i=1;i<=MAXN;i++)
{
miu[i]=1;
v[i]=0;
}
for(int i=2;i<=MAXN;i++)
{
if(v[i])
continue;
miu[i]=-1;
for(int j=2*i;j<=MAXN;j+=i)
{
v[j]=1;
if((j/i)%i==0)
miu[j]=0;
else
miu[j]*=-1;
}
}
for(int i=1;i<=MAXN;i++)
{
sum[i]=sum[i-1]+miu[i];
}
}
int main()
{
Moblus();
int T;
scanf("%d",&T);
while(T--)
{
int a,b,c,d,k;
ll ans=0;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
a--,c--;
a/=k,b/=k,c/=k,d/=k;
int tmp;
tmp=min(b,d);
for(int i=1,last=1;i<=tmp;i=last+1)
{
last=min(b/(b/i),d/(d/i));
ans+=1ll*(sum[last]-sum[i-1])*(b/i)*(d/i);
}
tmp=min(a,d);
for(int i=1,last=1;i<=tmp;i=last+1)
{
last=min(a/(a/i),d/(d/i));
ans-=1ll*(sum[last]-sum[i-1])*(a/i)*(d/i);
}
tmp=min(b,c);
for(int i=1,last=1;i<=tmp;i=last+1)
{
last=min(b/(b/i),c/(c/i));
ans-=1ll*(sum[last]-sum[i-1])*(b/i)*(c/i);
}
tmp=min(a,c);
for(int i=1,last=1;i<=tmp;i=last+1)
{
last=min(a/(a/i),c/(c/i));
ans+=1ll*(sum[last]-sum[i-1])*(a/i)*(c/i);
}
printf("%lld\n",ans);
}
return 0;
}