容斥原理求一个数互质的数个数

1160: Confusion in the Problemset

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 107   Solved: 15
[ Submit][ Status][ Web Board]

Description

You are in an m x n grid. You are standing in position (0, 0) and in each of the other lattice points (points with integer co-ordinates) an enemy is waiting. Now you have a ray gun that can fire up to infinity and no obstacle can stop it. Your target is to kill all the enemies. You have to find the minimum number of times you have to fire to kill all of them. For a 4 x 4 grid you have to fire 13 times. See the picture below:

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case contains two integers m, n (0 ≤ m, n ≤ 109) and at least one of them will be less than or equal to 106.

Output

For each case, print the case number and the minimum number of times you have to fire to kill all the enemies.

Sample Input

24 410 10

Sample Output

Case 1: 13Case 2: 65

HINT

Source

LOJ1144



#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

typedef long long lld;
const int maxn=1000005;
bool mk[maxn];
int f[maxn];
int p[maxn];
int a[maxn];

void Gao()
{
	int i,j;
	for(i=1;i<maxn;i++)
	{
		p[i]=1; mk[i]=0;
	}
	for(i=2;i<maxn;i++)
		if(!mk[i])
		{
			p[i]=f[i]=i;
			for(j=i*2;j<maxn;j+=i)
			{
				f[j]=i;//记录j的最大质因子i
				mk[j]=1;
				p[j]*=i;//质因子的积
			}
		}
}

int main()
{
	int T;
	int cas=1,num,n,m;
	int i,j,k;
	int fact[15];
	lld ans;
	Gao();
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		if(n>m)	n^=m^=n^=m;
		if(n==0 ||m==0)
		{
			printf("Case %d: %d\n",cas++,(m^n)!=0);
			continue ;
		}
		ans=2;
		for(i=1;i<=n;i++)	
		{
			if(i==p[i])
			{
				a[i]=num=0;	
				for(j=i;j!=1;j/=f[j])//求i的质因子
					fact[num++]=f[j];
				for(j=0;j<(1<<num);j++)//容斥原理
				{
					int tmp=1,sign=1;
					for(k=0;k<num;k++)
						if(j&(1<<k))
						{
							tmp*=fact[k];
							sign=-sign;
						}
					a[i]+=m/tmp*sign;
				}
			}
			ans+=a[p[i]];
		}
		printf("Case %d: %lld\n",cas++,ans);
	}
	return 0;
}

标程

#include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    struct point
    {
        int x,cnt;
        friend bool operator<(const point &p,const point &q){
            return p.x<q.x;
        }
    }c[1000010];
    int a[1100010],pri[1100010];
    void prime()
    {
        memset(a,0,sizeof(a));
        int i,j;
        for(i=2;i*i<=1100000;i++)
            if(!a[i])
                for(j=i*i;j<=1100000;j+=i)
                    a[j]=1;
        for(i=0,j=2;j<=1100000;j++)
            if(!a[j]) pri[i++]=j;
    }
    int cnt=0;
    void dfs(int mul,int pos,int step)
    {
       
        c[cnt].cnt=step;
        c[cnt++].x=mul;
        int up=1000000/mul;
        for(int i=pos;pri[i]<=up;i++){
            dfs(mul*pri[i],i+1,step+1);
        }
    }
    int main()
    {
        prime();
        dfs(1,0,0);
        sort(c,c+cnt);
        int t;
        scanf("%d",&t);
        for(int k=1;k<=t;k++){
            long long n,m,ans=0;
            scanf("%lld%lld",&n,&m);
            for(int i=0;i<cnt;i++)
                if(c[i].x>min(n,m)) break;
                else if(c[i].cnt&1) ans-=(n/c[i].x)*(m/c[i].x);
                else ans+=(n/c[i].x)*(m/c[i].x);
            if(n==0&&m==0) ans=0;
            else if(n==0||m==0) ans=1;
            else ans+=2;
            printf("Case %d: %lld\n",k,ans);
        }
        return 0;
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值