题目描述
两个整数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
" , ans / 2) ;
return 0 ;
}