2020寒假【gmoj1671】【友好数对】【容斥原理】

题目描述

在顺利完成家庭作业以后,Mirko感到非常的厌倦。所以,他列出了N个数,这些数中有些数对他是喜欢的,有些数对他是不喜欢的。

他喜欢的数对叫做友好数对,如果两个数至少有一个相同的数字(不要求在相同的位置),那么这两个数就是友好数对。请帮助Mirko在这N个数找出有多少友好数对。

输入

第一行一个正整数N(1<=N<=1000000)。

接下来N行,每行一个正整数,范围在1到1018之间。N个数中任意两个数都是不同的。

输出

只有一行一个整数,表示友好数对的个数。
2020寒假【gmoj1671】【友好数对】【容斥原理】_第1张图片

分析

友好数对一点都不友好。。
这题没得暴力。。经讲解,这题是容斥原理(上个友链)。因为最多不超过1023((1<<10)-1),数组就开1024。然后存对应位。循环一下,是0就不做,然后判断i,j相等关系,不相等直接乘。然后在一层循环的最后,补上乘。
注意:最后输出ans的时候要玄学/2,我也不知道为啥。。。

上代码

#include
#include
#include
using namespace std;
long long num[1024],n,s,f[1024],ans,sum;
int main()
{
	freopen("kompici.in","r",stdin);
	freopen("kompici.out","w",stdout);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	long long x,y,z; 
    	cin>>x;
    	z=0;
    	while(x>0)
    	{
    		y=x%10;
    		x=x/10;
    		z=z|(1<<y);
		}
		num[z]++;
	}
	for(int i=1;i<=1023;i++)
	{
		if(num[i]==0) continue;
		for(int j=1;j<=1023;j++)
		{
			if((i&j)!=0&&num[j]>0&&i!=j)
			{
				ans+=num[i]*num[j];
			}
		}
		ans+=num[i]*(num[i]-1);
	}
	cout<<ans/2;
	fclose(stdin);
	fclose(stdout);
    return 0;
}

你可能感兴趣的:(纪中集训)