P7617 [COCI2011-2012#2] KOMPIĆI 题解

题目

链接

https://www.luogu.com.cn/problem/P7617

字面描述

题目描述

给定 N N N 个正整数 A 1 , A 2 , . . . , A N A_1,A_2,...,A_N A1,A2,...,AN,求有多少整数对 ( i , j ) (i,j) (i,j),满足以下条件:

  • 1 ≤ i < j ≤ N 1 \le i < j \le N 1i<jN
  • A i A_i Ai A j A_j Aj 至少有一位数字是相同的(不一定要在相同的数位)

输入格式

输入的第一行包含一个正整数 N N N

接下来 N N N 行,每行包含一个正整数 A i A_i Ai

输出格式

输出一行一个整数,表示满足条件的整数对。

样例 #1

样例输入 #1
3
4
20
44
样例输出 #1
1

样例 #2

样例输入 #2
4
32
51
123
282
样例输出 #2
4

提示

【样例解释】

样例 1 中,满足要求的整数对为 ( 1 , 3 ) (1,3) (1,3)

样例 2 中,满足要求的整数对为 ( 1 , 3 ) (1,3) (1,3) ( 1 , 4 ) (1,4) (1,4) ( 2 , 3 ) (2,3) (2,3) ( 3 , 4 ) (3,4) (3,4)

【数据范围】

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 1 0 6 1 \le N \le 10^6 1N106 1 ≤ A i ≤ 1 0 18 1 \le A_i \le 10^{18} 1Ai1018

【说明】

本题分值按 COCI 原题设置,满分 120 120 120

题目译自 COCI2011-2012 CONTEST #2 T4 KOMPIĆI

思路

部分分

创建一个cnt数组,针对每一个数分解掉他是否含0~9
在按照题目需求两数对拍这9个数,统计答案

所有分

上面的思路是好但是最高时间复杂度为O(10^15),爆超
我们在往深一层次想一想,每个数只需要维护10个状态0~9;
完全可以状态压缩;
将他压缩成二进制数后,存入一个大小为1024(2^10)的桶里;
再将0 ~ 1023和0 ~1023分别对拍一下,如果含有同一个数字,最终答案+= c n t i ∗ c n t j cnt_i*cnt_j cnticntj
最后对于每个i(0<=i<1023) 最终答案+= c n t i ∗ ( c n t i − 1 ) / 2 cnt_i*(cnt_i-1)/2 cnti(cnti1)/2 (自己的元素)

最终答案存的就是结果 最终答案存的就是结果 最终答案存的就是结果

代码实现

#include<bits/stdc++.h>
#define ll long long 
using namespace std;

const int maxn=1024+10;
const int M=1024;
int n,op;
ll x,ans;
int k[maxn];//桶
int main(){
	scanf("%d",&n);
	while(n--){
		scanf("%lld",&x);
		op=0;
		//状态压缩
		while(x){
			op|=1<<(x%10);
			x/=10;
		}
		//装进桶里
		++k[op];
	}
	//所有数对拍
	for(int i=0;i<M;i++){
		for(int j=i+1;j<M;j++){
		//如果有相同数字,更新答案
			if(i&j)ans+=(ll)k[i]*k[j];
		}
	}
	// 与自己在对拍,排列组合算答案
	for(int i=0;i<M;i++) ans+=(ll)k[i]*(k[i]-1)>>1;
	//输出答案
	printf("%lld\n",ans);
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_Yxz_

我只是一名ssfoier

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值