题意:n*m的格子,每个格子都种有一树,左下角坐标为(1,1)。问在(0,0)最多看到多少树。
显然,若(x,y)能被看到,那么(k*x,k*y),其中k>1都不能被看到。
因此,问题转化为求1<=x<=n且1<=y<=m有多个<x,y>满足gcd(x,y)=1。
那么可以从1~n枚举x,累计1~m中与x互质的个数。
对x分解素因子,容斥一下就好了。
1 #include<cstdio> 2 #include<vector> 3 #define MAXN 100010 4 typedef long long LL; 5 using namespace std; 6 vector<int> fac[MAXN]; 7 void Init() { 8 int i, j; 9 for (i = 0; i < MAXN; i++) 10 fac[i].clear(); 11 for (i = 2; i < MAXN; i++) { 12 if (fac[i].size()) 13 continue; 14 fac[i].push_back(i); 15 for (j = 2; i * j < MAXN; j++) 16 fac[i * j].push_back(i); 17 } 18 } 19 LL Gao(int x, int &k, int t) { 20 LL res; 21 int i; 22 res = 1; 23 for (i = k = 0; x; x >>= 1, i++) { 24 if (x & 1) { 25 k++; 26 res *= fac[t][i]; 27 } 28 } 29 return res; 30 } 31 LL Prime(int k, int m) { 32 int i, j, t; 33 LL ans, tmp; 34 t = (int) fac[k].size(); 35 ans = 0; 36 for (i = 1; i < (1 << t); i++) { 37 tmp = Gao(i, j, k); 38 if (j & 1) 39 ans += m / tmp; 40 else 41 ans -= m / tmp; 42 } 43 return m - ans; 44 } 45 int main() { 46 int c; 47 int n, m, i; 48 LL ans; 49 Init(); 50 scanf("%d", &c); 51 while (c--) { 52 scanf("%d%d", &n, &m); 53 ans = m; 54 for (i = 2; i <= n; i++) 55 ans += Prime(i, m); 56 printf("%I64d\n", ans); 57 } 58 return 0; 59 }