http://acm.hdu.edu.cn/showproblem.php?pid=2841
有一个n*m的方格,从(1,1)開始,每一个点有一棵树,一个人站在(0,0)点,问他能看到几棵树。当(0,0)和另外的点在一条直线上时他仅仅能看到近期的一棵。
题目意在求在m*n的方格中有多少种y/x,由于两个y/x相等的点仅仅能看到一个。有多少种y/x也就是有多少 个(x,y)x与y互质。当中(1<=x<=m,1<=n<=y)。
这样就上一题类似了,求一个区间[1,m]内与i的互质的数的个数。这里1<=i<=n。先求出与i不互质的,对i分解质因子然后容斥。
#include <stdio.h> #include <iostream> #include <map> #include <set> #include <bitset> #include <list> #include <stack> #include <vector> #include <math.h> #include <string.h> #include <queue> #include <string> #include <stdlib.h> #include <algorithm> #define LL __int64 //#define LL long long #define eps 1e-9 #define PI acos(-1.0) using namespace std; const LL INF = 1<<30; const int maxn = 100010; LL ans; int n,m; int fac[maxn]; int prime[maxn]; int facCnt; void getPrime() { bool flag[maxn]; memset(flag,false,sizeof(flag)); prime[0] = 0; for(int i = 2; i < maxn; i++) { if(flag[i] == false) prime[++prime[0]] = i; for(int j = 1; j <= prime[0]&&i*prime[j]<maxn; j++) { flag[i*prime[j]] = true; if(i % prime[j] == 0) break; } } } void getFac(int num) { int tmp = num; facCnt = 0; for(int i = 1; i <= prime[0] && prime[i]*prime[i] <= tmp; i++) { if(tmp % prime[i] == 0) { fac[facCnt++] = prime[i]; while(tmp%prime[i] == 0) tmp /= prime[i]; } if(tmp == 1) break; } if(tmp > 1) fac[facCnt++] = tmp; } LL solve(int m) { //队列数组 int que[110]; int l = 0; que[l++] = 1; for(int i = 0; i < facCnt; i++) { int k = l; for(int j = 0; j < k; j++) que[l++] = fac[i]*que[j]*(-1); } LL anw = 0; for(int i = 0; i < l; i++) anw += m/que[i]; return anw; } int main() { int test; scanf("%d",&test); getPrime(); for(int item = 1; item <= test; item++) { scanf("%d %d",&n,&m); if(n > m) swap(n,m); ans = 0; for(int i = 1; i <= n; i++) { getFac(i); ans += solve(m); } printf("%I64d ",ans); } return 0; }