• [poj3904]Sky Code_状态压缩_容斥原理


    Sky Code poj-3904

        题目大意:给你n个数,问能选出多少满足题意的组数。

        注释:如果一个组数满足题意当且仅当这个组中有且只有4个数,且这4个数的最大公约数是1,$1le nle 10^4$。

          想法:我们显然可以知道4个数是可以不用两两互质的,所以正面计算难度较大,我们考虑从反面考虑。我们通过计算所有gcd不为1的组数,用总组数相减即可。然后,我们发现一个不为0的gcd显然可以被组中的任意一个数整除,所以我们可以进行容斥。只需要枚举gcd的约数个即可。计算的过程我们用状态压缩实现。

        最后,附上丑陋的代码... ...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxn 10005 
    using namespace std;
    typedef long long ll;
    ll a[10010];//记录单个数的质因数
    ll cnt;//记录单个数的质因数个数
    ll ans[10010][2];//ans[i][0]表示包含i这个因子的数的个数,ans[i][1]表示i的质因子个数
    ll Calc(ll x)//计算C[n][4]
    {
    	return x*(x-1)*(x-2)*(x-3)/24;
    }
    void separate(ll x)//分解质因数,由于我们在后面需要用cnt进行状态压缩,所以a数组从0开始记录
    {
    	for(int i=2;i*i<=x;i++)
    	{
    		if(x%i==0)
    		{
    			a[cnt]=i;
    			cnt++;
    			while(x%i==0)
    			{
    				x/=i;
    			}
    		}
    	}
    	if(x>1) a[cnt++]=x;
    }
    void dispose(ll x)
    {
    	cnt=0;
    	separate(x);
    	for(int i=1;i<(1<<cnt);i++)//通过枚举当前全集来统计桶
    	{
    		ll flag=0,middle=1;
    		for(int j=0;j<cnt;j++)
    		{
    			if(i&(1<<j))
    			{
    				flag++;
    				middle*=a[j];
    			}
    		}
    		ans[middle][0]++;
    		ans[middle][1]=flag;
    	}
    }
    int main()
    {
    	ll n;
    	while(~scanf("%lld",&n))
    	{
    		memset(ans,0,sizeof ans);
    		ll x;
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%lld",&x);
    			dispose(x);
    		}
    		ll answer=Calc(n);
    		for(int i=2;i<=maxn/4;i++)
    		{
    			if(ans[i][0])//Important
    			{
    				if(1&ans[i][1]) answer-=Calc(ans[i][0]);//如果是偶数个质因子
    				else answer+=Calc(ans[i][0]);//如果是奇数个质因子
    			}
    		}
    		// puts("Fuck");
    		printf("%lld
    ",answer);//输出答案即可
    	}
    	return 0;
    }
    

         小结:如果一个问题极其复杂,我们不妨反其道而行之。容斥原理就是一例。

  • 相关阅读:
    第七章之main函数和启动例程
    第一章之系统调用、库函数、内核函数区别
    unp第七章补充之socket tcp 产生 rst响应的情况
    unp第七章补充之TCP半开连接与半闭连接
    Qt 布局管理器
    Qt setMargin()和setSpacing() 的含义
    工作感悟
    关于数组数据常用的技巧
    正则表达式练习
    call/apply应用-对象使用原型链上的方法
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8604165.html
Copyright © 2020-2023  润新知