hdu 2841(容斥原理)

/*
    hdu 2841
    题意大概是
    你站在(0,0)点
    给你一个以(11,1)为顶点n*m的方格
    每个交点处都有一棵树
    问你能看到几棵树
    假设有两棵树
    他们的坐标分别为(x1,y1)(x2,y2)(x1>x2 y1>y2)
    若(0,0)->(x1,y1)和(0,0)->(x2,y2)两个向量平行
    那么后面的那个就看不到了
    列出平行的式子:
    x1=k*x2 y1=k*y2
    所以只需要x1 y1互质
    那么就不平行
    我们就能看到
    以上就是思路


    实现方法如下
    只要对每一行进行枚举
    把每一行能看到多少个求出来再相加就行
    每一行怎么求
    我们可以把每个数先进行质因子分解
    然后自由组合先算出有公约数(不互质)的有多少组
    再用总数减就行————容斥原理
    先算出每
*/
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<stdio.h>
#include<math.h>
#define ll long long
#define INF 2147483647
#define N 50
#define PI acos(-1)
#define EPS 1e-8
using namespace std;


int work(int a,int b)
{
    int prime[7];
    int p=0;
    for(int i=2;i*i<=b;i++)
    {
        if(b%i)
            continue;
        while(b%i==0)
            b/=i;
        prime[p++]=i;
    }
    if(b>1)
        prime[p++]=b;
    int res=0;
    for(int i=1;i<(1<<p);i++)
    {
        int tmp=1,cnt=0;
        for(int j=0;j<p;j++)
        {
            if(((i>>j)&1)==0)
                continue;
            tmp*=prime[j];
            cnt++;
        }
        if(cnt%2==0)
            res=res-a/tmp;
        else
            res=res+a/tmp;
    }
    return a-res;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        ll ans=0;
        for(int i=1;i<=n;i++)
            ans=ans+work(m,i);
        cout<<ans<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值