2015-05-14 20:54:08
题目:题意是一个人站在 (0,0),有一片 m×n 的树林,每个格点上有树,问这个人能看到多少棵树(后面的树会被前面的树挡住)
思路:注意到对于某一列 a,它有 (a,1) , (a,2) .... (a,n),注意到如果 gcd(a,k) = g (g!= 1),那么必定存在位置为 (a/g,k/g) 的数将其挡住。
那么问题就转化成了,对于每一列 a,求 n 以内与 a 互质的数的个数。那么就是转化成和 hdu 1796 一样的经典容斥问题了。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 100; int n,m; int fact[MAXN],dcnt; ll res; void Dfs(int p,int v,int cnt){ if(p > dcnt){ if(cnt == 0) return; //printf("v,cnt : %d %d\n",v,cnt); if(cnt & 1) res += n / v; else res -= n / v; return; } Dfs(p + 1,v,cnt); Dfs(p + 1,v * fact[p],cnt + 1); } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d%d",&m,&n); ll ans = 0; for(int i = 1; i <= m; ++i){ dcnt = 0; int t = i; for(int j = 2; j * j <= i; ++j) if(t % j == 0){ while(t % j == 0) t /= j; fact[++dcnt] = j; } if(t != 1) fact[++dcnt] = t; res = 0; Dfs(1,1,0); ans += n - res; } printf("%I64d\n",ans); } return 0; }