HDU--2841(容斥原理)

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

 

posted @ 2015-05-14 20:58  Naturain  阅读(117)  评论(0编辑  收藏  举报