问题 C: 数对

题目描述
两个整数A,B,如果他们某⼀数字相同了,那么(A,B)就是⼀组合法的数对(没有顺序),现在给定了N个整数,问存在多少对合法的数对呢?

输入
第⼀⾏,⼀个整数N。
接下来N⾏,每⾏⼀个正整数。

输出
输出⼀个整数,表示合法数对个数。

样例输入
复制样例数据
3
12
1
2
样例输出
2

提示
对于100%的数据,N≤1000000,每个正整数≤1018。

两个数能够成为合法的数对, 那么按照题目意思肯定是含有相同的数字, 这个数字肯定是0-9里面的,可能含有多个, 但是含有一个相同的, 和含有多个相同的,没有区别,或者说对他俩成为一对没有影响,因为这两个情况都能够是这两个数成为合法的数对, 那么怎么表示呢,怎么表示他俩含有相同的数字,这个时候就用到二进制了, 众所周知,如果1 << x == 1 , 那么这个公式可以用来表示第x位存在 , 在这个题目里可以用来表示该数含有该数字,再加上含有多个相同的数字和含有一个相同的数字效果相同, 那么我们就是1 << 10 ,这个范围来表示该数字含有哪些数字,比如110101 , 含有0 , 2 , 4 , 5 , 如果该数字里面还有个2, 则不影响该二进制数的值,只要 p |= 1 << (a % 10) , 就是该二进制与上一个尾数所表达的内容,并用num[p] ++ 记录一下这种数字的个数
最后我们就暴力枚举这1 << 10 , 个数, n ^ 2 复杂度,不会超时 ,i , j <= 1 << 10 , 如果i == j了, 那么就表示这个i所代表的数字有num[i] 个, 两两配对, 就是num[i] * (num[i] - 1) , 这个含有重复的,最后除以2 , 如果i & j 存在, 那么就表示这两个含有相同的数字, 那么我们就是直接加上num[i] * num[j] , , 这个也有重复的,最后结果除以2 ,

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll ;
ll num[11200] ;
int main()
{
	int n ;
	cin >> n ;
	for(int i = 1 ;i <= n ;i ++)
	 {
	 	ll a ;
	 	cin >> a ;
	 	ll p = 0 ;
	 	while(a)
	 	 {
	 	 	p |= 1 << (a % 10) ;
	 	 	a /= 10 ;
		 }
		 num[p] ++ ;
	 }
	 ll m = 1 << 10 ; 
	 ll ans = 0 ;
	 for(int i = 1 ;i <= m ;i ++)
	  for(int j = 1 ;j <= m ;j ++)
	    if(i == j)
	     ans += num[i] * (num[i] - 1) ;
	    else if(i & j)
	     ans += num[i] * num[j] ;
	printf("%lld\n" , ans / 2) ;
	return 0 ;
} 
posted @ 2019-10-11 13:17  spnooyseed  阅读(134)  评论(0编辑  收藏  举报