uva 10820 Send a Table
数论题(筛法求救欧拉函数)
题意:输入n,[1,50000],定义一个二元组(x,y),满足1<=x,y<=n , 且x和y互质 , 要求输出二元组的个数。注意好像(2,3),(3,2)算作两个答案,所以我们只要求出一组答案再乘以2即可
关键是怎么找出这个二元组,其实就是筛法求欧拉函数
我们约定x<y且x与y互质,那么我们将y从1枚举到n,对于每个y,找出所有小于它并且与它互质的x的个数,这不就是求y的欧拉函数吗?而y从1到n,不就是求n以内所有数字的欧拉函数吗?
所以最后的答案,就是n以内每个数字的欧拉函数值的累加和*2-1,没什么减1,是因为一个特殊的数字1,1的欧拉函数值为1(它本身),在x2过程中算了两次(1,1)要减去一个。
因为数据固定在50000以内,所以我们先用筛法50000以内数字的欧拉函数值保存下来,然后再读入case , 时间是0.024s
//筛法构建欧拉函数 #include <cstdio> #include <cstring> #include <cmath> #define N 50000 int phi[N+10]; void init() //先用筛法算出50000以内每个数字的欧拉函数值 { memset(phi,0,sizeof(phi)); phi[1]=1; for(int i=2; i<=N; i++) if(!phi[i]) //质因子 for(int j=i; j<=N; j+=i) { if(!phi[j]) phi[j]=j; phi[j]=phi[j]/i*(i-1); } return ; } int main() { int n; init(); while(scanf("%d",&n)!=EOF && n) { int ans=0; for(int i=1; i<=n; i++) ans+=phi[i]; ans=ans*2-1; printf("%d\n",ans); } return 0; }
甚至我们可以用递推的思想,把50000以内的累加和都事先保存下来,需要的时候再x2-1 , 时间0.012s
//筛法构建欧拉函数 #include <cstdio> #include <cstring> #include <cmath> #define N 50000 int phi[N+10]; int sum[N+10]; void init() //先用筛法算出50000以内每个数字的欧拉函数值 { memset(phi,0,sizeof(phi)); phi[1]=1; for(int i=2; i<=N; i++) if(!phi[i]) //质因子 for(int j=i; j<=N; j+=i) { if(!phi[j]) phi[j]=j; phi[j]=phi[j]/i*(i-1); } sum[1]=1; for(int i=2; i<=N; i++) sum[i]=sum[i-1]+phi[i]; return ; } int main() { int n; init(); while(scanf("%d",&n)!=EOF && n) printf("%d\n",sum[n]*2-1); return 0; }