【SP10069】题解
题解
思路
不用关心每个数的每一位是什么、哪几位相同,我们只需记录每个数出现了哪几个数字,可以使用类似于状态压缩的思想记录每个数的状压形式,比如一个数为 $(4)_{10}$,那么他的状态压缩形式为 $(00001)_2$。
当两个数在状态压缩表示下有一位相同,我们就认为这两个数是一对,每个二进制数可以化为 $1 \sim 2^{10}$,所以开一个标记数组记录。
然后在 $1 \sim 2^{10}$ 的范围内枚举两个数,如果 $i \operatorname{and} j \ne 0$ 且 $i \ne j$,就用乘法原理更新答案,如果 $i=j$,也就是答案应该更新为 $ans = ans + \frac{cnt_i \times cnt_{i - 1}}{2}$,表示把每个 $cnt_i$ 跟 $cnt_i$ 配上。
输入处理:
for (int i = 1; i <= n; i++){
cin >> x;
while (x){
a[i] |= 1ll << (x % 10);
x /= 10;
}
cnt[a[i]]++;
}
枚举两个数
long long ans = 0;
for (int i = 1; i < INF; i++){
for (int j = i; j < INF; j++){
if (i & j && i != j){
ans += cnt[i] * cnt[j];
}
if (i == j){
ans += cnt[i] * (cnt[i] - 1) / 2;
}
}
}
AC Code
#include<iosteam>
using namespace std;
const int MAXN = 1e6 + 10,INF = 1024;
int n,a[MAXN];
long long x,cnt[MAXN];
int main(){
cin >> n;
for (int i = 1; i <= n; i++){
cin >> x;
for (; x; x /= 10){
a[i] |= 1ll << (x % 10); // 状压
}
cnt[a[i]]++; // 统计
}
long long ans = 0;
for (int i = 1; i < INF; i++){
for (int j = i; j < INF; j++){
if (i & j && i != j){ // 如果两个不相同的数可以配成一对
ans += cnt[i] * cnt[j]; // 乘法原理更新答案
}
if (i == j){ // 自己跟自己配一对
ans += cnt[i] * (cnt[i] - 1) / 2; // 更新答案
}
}
}
cout << ans;
return 0;
}

浙公网安备 33010602011771号