hdu1695 两个区间各取一个数gcd==k对数:莫比乌斯反演

首先(1,b)(1,d)->(1,b/k)(1,d/k)转化为互质对数

设F(k)为gcd(x,y)为k的倍数的对数->F(k)=(b/k)*(d/k)

f[1]=mu[1]*F[1]+mu[2]*F[2]+...mu[m]*F[m]

再减去重复计算的,变了F[i]再做一遍==

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 #define maxn 100005
 6 #define LL long long
 7 LL vis[maxn],prime[maxn],mu[maxn];
 8 void mobius()
 9 {
10   LL cnt=0,i,j;
11   memset(vis,0,sizeof(vis));
12   mu[1]=1;
13   for (i=2;i<=maxn;i++){
14     if (vis[i]==0){
15       prime[++cnt]=i;
16       mu[i]=-1;
17     }
18     for (j=1;j<=cnt;j++){
19       if (i*prime[j]>maxn) break;
20       vis[i*prime[j]]=1;
21       if (i%prime[j]==0){mu[i*prime[j]]=0; break;}
22       else mu[i*prime[j]]=-mu[i];
23     }
24   }
25 }
26 int main()
27 {
28   LL T,t,a,b,c,d,k,a1,a2,i;
29   mobius();
30   scanf("%I64d",&T);
31   for (t=1;t<=T;t++){
32     scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&k);
33     printf("Case %I64d: ",t);
34     if (k==0) {printf("0\n"); continue; }
35     b/=k; d/=k;
36     if (b>d) swap(b,d);
37     a1=a2=0;
38     for (i=1;i<=b;i++){
39       a1+=mu[i]*(b/i)*(d/i);
40       a2+=mu[i]*(b/i)*(b/i);
41     }
42     printf("%I64d\n",a1-a2/2);
43   }
44   return 0;
45 }
View Code

关于莫比乌斯反演专题学习和理解过两天再补,好困要碎TUT

很久以前写的一个容斥版本,也放上来吧,(对比发现跑的好慢

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 int temp,d,a,sum,num[100005],prime[100005],vis[100005];
 5 long long gcd(long long x,long long y)
 6 {
 7     if (y==0) return x;
 8     return gcd(y,x%y);
 9 }
10 void dfs(int now,int flag,long long bei)
11 {
12     if (bei>d) return;
13     if (flag) temp+=d/bei-a/bei;
14     else temp-=d/bei-a/bei;
15     for (int i=now+1;i<=sum;i++)
16         dfs(i,1-flag,num[i]/gcd(bei,num[i])*bei);
17 }
18 int main()
19 {
20     int cnt,i,j,T,t,k,b,c,sqr;
21     long long ans;
22     cnt=0;
23     memset(vis,0,sizeof(vis));
24     for (i=2;i<=100000;i++)
25         if (!vis[i])
26     {
27         cnt++;
28         prime[cnt]=i;
29         for (j=2;i*j<=100000;j++) vis[i*j]=1;
30     }
31     scanf("%d",&T);
32     for (t=1;t<=T;t++)
33     {
34         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
35         if (k==0) { printf("Case %d: 0\n",t); continue;}
36         b/=k; d/=k;
37         if (b>d) {a=b; b=d; d=a; }
38         if (b!=0) ans=d; else ans=0;
39         for (i=2;i<=b;i++)
40         {
41             a=i; sum=0;
42             sqr=(int)sqrt(1.0*a);
43             for (j=1;j<=cnt&&prime[j]<=sqr;j++)
44                 if (a%prime[j]==0)
45             {
46                 sum++;
47                 num[sum]=prime[j];
48                 while (a%prime[j]==0) a/=prime[j];
49             }
50             if (a!=1) {sum++; num[sum]=a; }
51             temp=0;  a=i;
52             for (j=1;j<=sum;j++) dfs(j,1,num[j]);
53             ans=ans+(long long)(d-a-temp);
54         }
55         printf("Case %d: %I64d\n",t,ans);
56     }
57 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695

posted on 2015-04-14 03:49  xiao_xin  阅读(249)  评论(0编辑  收藏  举报

导航