1. 程式人生 > >HDU - 2841 - Visible Trees(容斥)

HDU - 2841 - Visible Trees(容斥)

There are many trees forming a m * n grid, the grid starts from (1,1). Farmer Sherlock is standing at (0,0) point. He wonders how many trees he can see.

If two trees and Sherlock are in one line, Farmer Sherlock can only see the tree nearest to him.
Input
The first line contains one integer t, represents the number of test cases. Then there are multiple test cases. For each test case there is one line containing two integers m and n(1 ≤ m, n ≤ 100000)
Output


For each test case output one line represents the number of trees Farmer Sherlock can see.
Sample Input
2
1 1
2 3
Sample Output
1
5
題目連結
參考題解1
參考題解2
參考題解3
這裡提供了3個題解,兩種做法,都是比較詳細的,我採用了第一個題解的做法。
題目:給一個含有N*M個點的矩陣,左下角的點為(1,1),右上角的點為(N,M),一個人站在(0,0)點看這些點,在一條直線上,他只能看到最前邊的點,後邊的點都被擋住看不到了。那麼問題來了:這個人總共能看到多少個點?

思路:那麼我們可以找下規律,他能看到的一定是x,y座標互素的點,因為如果不互素,那麼就說明他是某個點的倍數,那麼他一定是被這個點擋住了,看不見。所以我們就可以求m行裡面與n互素的數,每一行都做一次容斥,加和就可以了。

這是我的另一篇部落格,用了另一種方法,當然不是這個題目的,只是闡述方法。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int maxn = 1e6 + 1e5;
LL que[maxn], factor[maxn], num;

void Divid(LL n)
{
    num = 0;
    for(LL i = 2; i * i <= n; ++i)
    {
        if(n % i == 0)
        {
            while(n % i == 0)
                n /= i;
            factor[num++] = i;
        }
    }
    if(n != 1)
        factor[num++] = n;
}

LL solve(LL n)
{
    LL k, t, ans;
    t = ans = 0;
    que[t++] = -1;
    for(LL i = 0; i < num; ++i)	//外迴圈遍歷所有的因子
    {
        k = t;
        for(LL j = 0; j < k; ++j)	//我們這裡每次都是基於前面的乘積,所以這樣下來就把所有情況都遍歷完了
            que[t++] = -1 * que[j] * factor[i];
    }
    for(LL i = 1; i < t; ++i)
        ans += n / que[i];
    return ans;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        LL n, m, ans;
        scanf("%lld%lld", &n, &m);
        if(n < m)
            swap(n, m);
        ans = n;
        for(LL i = 2; i <= m; ++i)
        {
            Divid(i);
            ans += (n - solve(n));
        }
        printf("%lld\n",ans);
    }
    return 0;
}