hdu-2841 Visible Trees---容斥定理

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=2841

题目大意:

N*M的格点上有树,从0,0点可以看到多少棵树。

解题思路:

发现如果A1/B1=A2/B2那么就有一棵树看不到,所以就是找出Ai/Bi有多少种。

如果A,B有大于1的公约数,则A=A'*D B=B'*D,那么A/B=A'/B',也就是存在另外一组数和这种相等,则问题转换成有多少对互质的数。

求1-m中有多少个与1-n中互质的数目,

可以枚举m,每次求1-n中与m互质的数目。(HDU-4135简单版

初始化:m = 1的时候,答案就是n

 1 #include<iostream>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e6 + 10;
 5 ll a[50], tot;
 6 ll gcd(ll a, ll b)
 7 {
 8     return b == 0 ? a : gcd(b, a % b);
 9 }
10 void init(ll n)//求出n的素因子
11 {
12     tot = 0;
13     for(ll i = 2; i * i <= n; i++)
14     {
15         if(n % i == 0)
16         {
17             a[tot++] = i;
18             while(n % i == 0)n /= i;
19         }
20     }
21     if(n != 1)a[tot++] = n;
22 }
23 ll sum(ll m)//求[1, m]中与n互质的个数
24 {
25     ll ans = 0;
26     for(int i = 1; i < (1 << tot); i++)//a数组的子集
27     {
28         ll num = 0;
29         for(int j = i; j; j >>= 1)if(j & 1)num++;//统计i的二进制中1的个数
30         ll lcm = 1;
31         for(int j = 0; j < tot; j++)
32             if((1 << j) & i)
33         {
34             lcm = lcm / gcd(lcm, a[j]) * a[j];
35             if(lcm > m)break;
36         }
37         if(num & 1)ans += m / lcm;//奇数加上
38         else ans -= m / lcm;//偶数减去
39     }
40     return m - ans;
41 }
42 ll n, m;
43 int main()
44 {
45     int T, cases = 0;
46     cin >> T;
47     while(T--)
48     {
49         cin >> n >> m;
50         //if(n < m)swap(n, m);
51         ll ans = n;
52         for(int i = 2; i <= m; i++)
53         {
54             init(i);
55             ans += sum(n);
56         }
57         cout<<ans<<endl;
58     }
59     return 0;
60 }
原文地址:https://www.cnblogs.com/fzl194/p/9075280.html