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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值