您的位置:首页 > 其它

【bzoj2694】Lcm 莫比乌斯反演

2017-03-06 17:46 302 查看
题目大意:对于任意的>1的n gcd(a, b)不是n^2的倍数,的1到a和1到b的lcm(a,b)之和。

题解:又是一道变态题。。。。。。。。。。

可以参考同系列的上一篇文章,这题主要的特殊处在于不能出现gcd(a,b)为n^2倍数的lcm(a,b),通过一顿瞎搞我们发现最后要求的前缀和中多出了一个abs(u(D/i)),这还是一个积性函数,唯一不同的是i中包含prime[j]的情况,这个我们就找规律,如果一个数中包含三个一样的因子的话无论如何两个u中一定有一个包含两个一样的因子,那么表达式为0,所以出现这种情况的话最后一定为0。如果只有两个一样的因子的时候我们可以看出只有当两个u中各包含一个该因子的时候表达式才有值,再通过这个瞎推一下就行了。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int sum[4001000];
int prime[400100];
bool pd[4001000];
int top=0;
void shai()
{
sum[1]=1;
for(int i=2;i<=4000000;i++)
{
if(!pd[i])
{
prime[++top]=i;
sum[i]=i-i*i;
}
for(int j=1;i*prime[j]<=4000000;j++)
{
pd[i*prime[j]]=true;
if(i%prime[j]==0)
{
int x=i/prime[j];
if(x%prime[j]==0) sum[i*prime[j]]=0;
else sum[i*prime[j]]=-prime[j]*prime[j]*prime[j]*sum[x];
break;
}
sum[i*prime[j]]=sum[i]*sum[prime[j]];
}
}
for(int i=1;i<=4000000;i++)
{
sum[i]=sum[i]+sum[i-1];
}
}
inline int Sum(int x,int y)
{
int mid1=x*(x+1)/2;
int mid2=y*(y+1)/2;
return mid1*mid2;
}
int solve(int n,int m)
{
int last;
int limit=min(n,m);
long long re=0;
for(int i=1;i<=limit;i=last+1)
{
last=min(n/(n/i),m/(m/i));
re=re+(sum[last]-sum[i-1])*Sum(n/i,m/i);
}
return re;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
shai();
int T;
scanf("%d",&T);
int n,m;
while(T--)
{
scanf("%d%d",&n,&m);
long long ans=solve(n,m);
printf("%d\n",ans&((1<<30)-1));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: