题目链接
分析:
之前写过约数个数和,加强版
用反演把 [gcd(i,j)=1] [ g c d ( i , j ) = 1 ] 化开
令 f(n,m)=∑ni=1ni[gcd(i,m)=1] f ( n , m ) = ∑ i = 1 n n i [ g c d ( i , m ) = 1 ]
f f 函数可以用 O(n) O ( n ) 的时间算出
总时间复杂度为 O(n2logn) O ( n 2 l o g n )
预处理gcd
因为 a,b,c a , b , c 没有顺序,所以我们可以选择两个较小的枚举
代码一开始以为会比较玄学,有分块之类的
实际上就是一个类似暴力的东西。。。
#include
#include
#include
using namespace std;
const int N=2005;
int a,b,c;
int mu[N],sshu[N],tot=0,gcd[N][N],f[N][N];
bool no[N];
int GCD(int a,int b){
int r=a%b;
while (r) {
a=b;b=r;r=a%b;
}
return b;
}
void prepare() {
mu[1]=1;
for (int i=2;iif (!no[i]) {
sshu[++tot]=i;
mu[i]=-1;
}
for (int j=1;j<=tot&&sshu[j]*ino[sshu[j]*i]=1;
if (i%sshu[j]==0) {
mu[i*sshu[j]]=0;
break;
}
mu[i*sshu[j]]=-mu[i];
}
}
for (int i=1;ifor (int j=i;jint F(int n,int m) {
if (f[n][m]!=-1) return f[n][m];
int ans=0;
for (int i=1;i<=n;i++)
if (gcd[i][m]==1) ans+=n/i;
f[n][m]=ans;
return ans;
}
int main()
{
prepare();
scanf("%d%d%d",&a,&b,&c);
if (a>b) swap(a,b);
if (b>c) swap(b,c);
if (a>b) swap(a,b);
memset(f,-1,sizeof(f));
int ans=0;
int last;
for (int i=1;i<=a;i++)
for (int j=1;j<=b;j++)
if (gcd[i][j]==1)
ans+=mu[j]*(a/i)*F(b/j,i)*F(c/j,i);
printf("%d\n",ans&((1<<30)-1));
return 0;
}