hiho一下 第144周(机会渺茫)解题报告及拓展
题目1 : 机会渺茫
时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi最近在追求一名学数学的女生小Z。小Z其实是想拒绝他的,但是找不到好的说辞,于是提出了这样的要求:对于给定的两个正整数N和M,小Hi随机选取一个N的约数N',小Z随机选取一个M的约数M',如果N'和M'相等,她就答应小Hi。
小Z让小Hi去编写这个随机程序,到时候她review过没有问题了就可以抽签了。但是小Hi写着写着,却越来越觉得机会渺茫。那么问题来了,小Hi能够追到小Z的几率是多少呢?
输入
每个输入文件仅包含单组测试数据。
每组测试数据的第一行为两个正整数N和M,意义如前文所述。
对于40%的数据,满足1<=N,M<=106
对于100%的数据,满足1<=N,M<=1012
输出
对于每组测试数据,输出两个互质的正整数A和B(以A分之B表示小Hi能够追到小Z的几率)。
- 样例输入
-
3 2
- 样例输出
-
4 1
Solution:
Way1:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 5 long ans=0,maxn,zhi[100000]; 6 7 void Get_Zhi() 8 { 9 long i,j; 10 bool vis[maxn+1]; 11 for (i=2;i<=maxn;i++) 12 vis[i]=true; 13 for (i=2;i<=maxn;i++) 14 { 15 if (vis[i]) 16 { 17 ans++; 18 zhi[ans]=i; 19 } 20 for (j=1;j<=ans;j++) 21 { 22 if (i*zhi[j]>maxn) 23 break; 24 vis[i*zhi[j]]=false; 25 if (i%zhi[j]==0) 26 break; 27 } 28 } 29 } 30 31 int main() 32 { 33 long long n,m,a,b,temp,x,y; 34 long i,g; 35 scanf("%lld%lld",&n,&m); 36 if (n>m) 37 maxn=(long)sqrt(n); 38 else 39 maxn=(long)sqrt(m); 40 Get_Zhi(); 41 if (n>m) 42 { 43 a=n; 44 b=m; 45 } 46 else 47 { 48 a=m; 49 b=n; 50 } 51 while (b) 52 { 53 temp=b; 54 b=a%b; 55 a=temp; 56 } 57 x=1; 58 y=1; 59 //a 60 if (a!=1) 61 { 62 for (i=1;i<=ans;i++) 63 if (a%zhi[i]==0) 64 { 65 g=1; 66 while (a%zhi[i]==0) 67 { 68 a/=zhi[i]; 69 g++; 70 } 71 x*=g; 72 if (a==1) 73 break; 74 } 75 //a,n,m都有该质数,且系数都为1(若系数大于1,则相乘大于最大值) 76 if (a!=1) 77 { 78 //x*2,y*4->x,y*2 79 y*=2; 80 n/=a; 81 m/=a; 82 } 83 } 84 85 //n 86 if (n!=1) 87 { 88 for (i=1;i<=ans;i++) 89 if (n%zhi[i]==0) 90 { 91 g=1; 92 while (n%zhi[i]==0) 93 { 94 n/=zhi[i]; 95 g++; 96 } 97 y*=g; 98 if (n==1) 99 break; 100 } 101 if (n!=1) 102 y*=2; 103 } 104 105 //m 106 if (m!=1) 107 { 108 for (i=1;i<=ans;i++) 109 if (m%zhi[i]==0) 110 { 111 g=1; 112 while (m%zhi[i]==0) 113 { 114 m/=zhi[i]; 115 g++; 116 } 117 y*=g; 118 if (m==1) 119 break; 120 } 121 if (m!=1) 122 y*=2; 123 } 124 125 a=y; 126 b=x; 127 while (b) 128 { 129 temp=b; 130 b=a%b; 131 a=temp; 132 } 133 x/=a; 134 y/=a; 135 printf("%lld %lld\n",y,x); 136 return 0; 137 }
Way2:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 5 long ans=0,maxn,zhi[100000]; 6 7 //打质数表! 8 9 void Get_Zhi() 10 { 11 long i,j; 12 bool vis[maxn+1]; 13 for (i=2;i<=maxn;i++) 14 vis[i]=true; 15 for (i=2;i<=maxn;i++) 16 { 17 if (vis[i]) 18 { 19 ans++; 20 zhi[ans]=i; 21 } 22 for (j=1;j<=ans;j++) 23 { 24 if (i*zhi[j]>maxn) 25 break; 26 vis[i*zhi[j]]=false; 27 if (i%zhi[j]==0) 28 break; 29 } 30 } 31 } 32 33 int main() 34 { 35 long long n,m,y=1; 36 long i,j,g1=0,g2=0,p[100],q[100],u[100],v[100]; 37 scanf("%lld%lld",&n,&m); 38 if (n>m) 39 maxn=(long)sqrt(n); 40 else 41 maxn=(long)sqrt(m); 42 Get_Zhi(); 43 44 //n 45 if (n!=1) 46 { 47 for (i=1;i<=ans;i++) 48 if (n%zhi[i]==0) 49 { 50 g1++; 51 p[g1]=i; 52 q[g1]=1; 53 while (n%zhi[i]==0) 54 { 55 n=n/zhi[i]; 56 q[g1]++; 57 } 58 if (n==1) 59 break; 60 } 61 } 62 if (n!=1) 63 y*=2; 64 65 //m 66 if (m!=1) 67 { 68 for (i=1;i<=ans;i++) 69 if (m%zhi[i]==0) 70 { 71 g2++; 72 u[g2]=i; 73 v[g2]=1; 74 while (m%zhi[i]==0) 75 { 76 m/=zhi[i]; 77 v[g2]++; 78 } 79 if (m==1) 80 break; 81 } 82 } 83 if (m!=1 && m!=n) 84 y*=2; 85 i=1; 86 j=1; 87 while (i<=g1 && j<=g2) 88 { 89 if (p[i]<u[j]) 90 { 91 y*=q[i]; 92 i++; 93 } 94 else if (u[j]<p[i]) 95 { 96 y*=v[j]; 97 j++; 98 } 99 else 100 { 101 if (q[i]>v[j]) 102 y*=q[i]; 103 else 104 y*=v[j]; 105 i++; 106 j++; 107 } 108 } 109 while (i<=g1) 110 { 111 y*=q[i]; 112 i++; 113 } 114 while (j<=g2) 115 { 116 y*=v[j]; 117 j++; 118 } 119 printf("%lld 1\n",y); 120 return 0; 121 }
Way3:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 5 long ans=0,maxn,zhi[100000]; 6 7 void Get_Zhi() 8 { 9 long i,j; 10 bool vis[maxn+1]; 11 for (i=1;i<=maxn;i++) 12 vis[i]=true; 13 for (i=2;i<=maxn;i++) 14 { 15 if (vis[i]) 16 { 17 ans++; 18 zhi[ans]=i; 19 } 20 for (j=1;j<=ans;j++) 21 { 22 if (i*zhi[j]>maxn) 23 break; 24 vis[i*zhi[j]]=false; 25 if (i%zhi[j]==0) 26 break; 27 } 28 } 29 } 30 31 int main() 32 { 33 long long n,m,a,b,temp,x,y; 34 long g,i,r=0,t,p[100],q[100]; 35 scanf("%lld%lld",&n,&m); 36 if (n>m) 37 maxn=(long)sqrt(n); 38 else 39 maxn=(long)sqrt(m); 40 Get_Zhi(); 41 if (n>m) 42 { 43 a=n; 44 b=m; 45 } 46 else 47 { 48 a=m; 49 b=n; 50 } 51 while (b) 52 { 53 temp=b; 54 b=a%b; 55 a=temp; 56 } 57 x=1; 58 y=1; 59 60 n/=a; 61 m/=a; 62 63 //a 64 r=0; 65 if (a!=1) 66 { 67 for (i=1;i<=ans;i++) 68 if (a%zhi[i]==0) 69 { 70 r++; 71 p[r]=i; 72 q[r]=1; 73 while (a%zhi[i]==0) 74 { 75 a/=zhi[i]; 76 q[r]++; 77 } 78 x*=q[r]; 79 if (a==1) 80 break; 81 } 82 //a,n,m都有该质数,且系数都为1(若系数大于1,则相乘大于最大值) 83 //x*2,y*4->x,y*2 84 if (a!=1) 85 y*=2; 86 } 87 p[r+1]=1000000; 88 89 //n 90 if (n!=1) 91 { 92 t=1; 93 for (i=1;i<=ans;i++) 94 if (n%zhi[i]==0) 95 { 96 g=1; 97 while (n%zhi[i]==0) 98 { 99 n/=zhi[i]; 100 g++; 101 } 102 //p[r+1]=1000000; 103 while (p[t]<i) 104 { 105 y*=q[t]; 106 t++; 107 } 108 if (p[t]==i) 109 { 110 y*=(g+q[t]-1); 111 t++; 112 } 113 else 114 y*=g; 115 if (n==1) 116 break; 117 } 118 if (n!=1) 119 y*=2; 120 while (t<=r) 121 { 122 y*=q[t]; 123 t++; 124 } 125 } 126 else 127 y*=x; 128 129 //m 130 if (m!=1) 131 { 132 t=1; 133 for (i=1;i<=ans;i++) 134 if (m%zhi[i]==0) 135 { 136 g=1; 137 while (m%zhi[i]==0) 138 { 139 m/=zhi[i]; 140 g++; 141 } 142 //p[r+1]=1000000; 143 while (p[t]<i) 144 { 145 y*=q[t]; 146 t++; 147 } 148 if (p[t]==i) 149 { 150 y*=(g+q[t]-1); 151 t++; 152 } 153 else 154 y*=g; 155 if (m==1) 156 break; 157 } 158 if (m!=1) 159 y*=2; 160 while (t<=r) 161 { 162 y*=q[t]; 163 t++; 164 } 165 } 166 else 167 y*=x; 168 169 a=y; 170 b=x; 171 while (b) 172 { 173 temp=b; 174 b=a%b; 175 a=temp; 176 } 177 x/=a; 178 y/=a; 179 printf("%lld %lld\n",y,x); 180 return 0; 181 } 182 /* 183 input: 184 16 8 185 output: 186 5 1 187 188 input: 189 60 48 190 output: 191 20 1 192 */
Advance:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 #define maxn 100000 5 #define maxs 100000 6 7 long zhi[maxn],z[maxs+1][12],g[maxs+1][12],ansz[maxs+1]; 8 9 void Get_Zhi() 10 { 11 long i,j,s,ans=0; 12 long long k; 13 bool vis[maxn+1]; 14 for (i=2;i<=maxn;i++) 15 vis[i]=true; 16 for (i=2;i<=maxn;i++) 17 { 18 if (vis[i]) 19 { 20 ans++; 21 zhi[ans]=i; 22 for (j=i;j<=maxs;j+=i) 23 { 24 ansz[j]++; 25 z[j][ansz[j]]=i; 26 //为了求约数总数,比正确个数多1 27 g[j][ansz[j]]=2; 28 } 29 k=(long long)i*i; 30 s=2; 31 while (k<=maxs) 32 { 33 for (j=k;j<=maxs;j+=k) 34 g[j][ansz[j]]++; 35 k=(long long)k*i; 36 s++; 37 } 38 } 39 for (j=1;j<=ans;j++) 40 { 41 if (i*zhi[j]>maxn) 42 break; 43 vis[i*zhi[j]]=false; 44 if (i%zhi[j]==0) 45 break; 46 } 47 } 48 } 49 50 int main() 51 { 52 long i,j,m,n; 53 double result=0,re; 54 for (i=1;i<=maxs;i++) 55 ansz[i]=0; 56 Get_Zhi(); 57 for (n=1;n<=maxs;n++) 58 for (m=1;m<=maxs;m++) 59 { 60 re=1.0; 61 i=1; 62 j=1; 63 while (i<=ansz[n] && j<=ansz[m]) 64 { 65 if (z[n][i]<z[m][j]) 66 { 67 re/=g[n][i]; 68 i++; 69 } 70 else if (z[n][i]>z[m][j]) 71 { 72 re/=g[m][j]; 73 j++; 74 } 75 else 76 { 77 if (g[n][i]>g[m][j]) 78 re/=g[n][i]; 79 else 80 re/=g[m][j]; 81 i++; 82 j++; 83 } 84 } 85 while (i<=ansz[n]) 86 { 87 re/=g[n][i]; 88 i++; 89 } 90 while (j<=ansz[m]) 91 { 92 re/=g[m][j]; 93 j++; 94 } 95 result+=re; 96 } 97 printf("%lf\n",result*1.0/maxs/maxs); 98 return 0; 99 }