【P7617】题解

题解

思路

不用关心每个数的每一位是什么、哪几位相同,我们只需记录每个数出现了哪几个数字,可以使用类似于状态压缩的思想记录每个数的状压形式,比如一个数为 $(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;
}
posted @ 2023-09-05 18:07  rksm2333  阅读(8)  评论(0)    收藏  举报  来源