莫比乌斯反演 BZOJ 2820

莫比乌斯反演真(TMD)难学。我自看了好长时间。

BZOJ 2820: YY的GCD

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1384  Solved: 718

Description

神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
傻×必然不会了,于是向你来请教……多组输入

Input

第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M

Output

T行,每行一个整数表示第i组数据的结果

Sample Input

2
10 10
100 100

Sample Output

30
2791

HINT

T = 10000

N, M <= 10000000

 1 typedef long long ll;
 2 #include<iostream>
 3 using namespace std;
 4 #include<cstdio>
 5 #include<cstring>
 6 const int N=10000010;
 7 bool IS_prim[N+10];
 8 int prim[N+10],cnt=0,mu[N+10],g[N+10],sum[N+10];
 9 int T;ll n,m;
10 void get_prim()
11 {
12      cnt=0;
13      memset(IS_prim,true,sizeof(IS_prim));
14      mu[1]=1;IS_prim[1]=false;
15      for(int i=2;i<N;++i)
16      {
17          if(IS_prim[i])
18          {
19              prim[cnt++]=i;
20              mu[i]=-1;g[i]=1;
21          }
22          for(int j=0;j<cnt&&i*prim[j]<N;++j)
23          {
24              IS_prim[i*prim[j]]=false;
25              if(i%prim[j])
26              {
27                  mu[i*prim[j]]=-mu[i];
28                  g[i*prim[j]]=mu[i]-g[i];
29              }
30              else
31              {
32                  mu[i*prim[j]]=0;
33                  g[i*prim[j]]=mu[i];
34                  break;
35              }
36          }
37          sum[i]=sum[i-1]+g[i];
38      }
39 }
40 int main()
41 {
42     get_prim();
43     scanf("%d",&T);
44     while(T--)
45     {
46         scanf("%d%d",&n,&m);
47         if(n>m) swap(n,m);
48         ll ans=0;
49         for(int i=1,last;i<=n;i=last+1)
50         {
51             last=min(n/(n/i),m/(m/i));
52             ans+=(n/i)*(m/i)*(sum[last]-sum[i-1]);
53         }
54         printf("%lld\n",ans);
55     }
56     return 0;
57 }

 

posted @ 2016-06-04 11:41  csgc0131123  阅读(165)  评论(0编辑  收藏  举报