【LG-P7617】题解

发布时间 2023-10-09 22:16:01作者: Codehyx

题解

思路

不用关心每个数的每一位是什么、哪几位相同,我们只需记录每个数出现了哪几个数字,可以使用类似于状态压缩的思想记录每个数的状压形式,比如一个数为 \((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;
}