题解
思路
不用关心每个数的每一位是什么、哪几位相同,我们只需记录每个数出现了哪几个数字,可以使用类似于状态压缩的思想记录每个数的状压形式,比如一个数为 \((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;
}
标签:LG,cnt,10,int,题解,long,ans,P7617
From: https://www.cnblogs.com/codehyx-blog/p/solution-lg_p7617.html