zoukankan      html  css  js  c++  java
  • 问题 C: 数对

    题目描述
    两个整数A,B,如果他们某⼀数字相同了,那么(A,B)就是⼀组合法的数对(没有顺序),现在给定了N个整数,问存在多少对合法的数对呢?

    输入
    第⼀⾏,⼀个整数N。
    接下来N⾏,每⾏⼀个正整数。

    输出
    输出⼀个整数,表示合法数对个数。

    样例输入
    复制样例数据
    3
    12
    1
    2
    样例输出
    2

    提示
    对于100%的数据,N≤1000000,每个正整数≤1018。

    两个数能够成为合法的数对, 那么按照题目意思肯定是含有相同的数字, 这个数字肯定是0-9里面的,可能含有多个, 但是含有一个相同的, 和含有多个相同的,没有区别,或者说对他俩成为一对没有影响,因为这两个情况都能够是这两个数成为合法的数对, 那么怎么表示呢,怎么表示他俩含有相同的数字,这个时候就用到二进制了, 众所周知,如果1 << x == 1 , 那么这个公式可以用来表示第x位存在 , 在这个题目里可以用来表示该数含有该数字,再加上含有多个相同的数字和含有一个相同的数字效果相同, 那么我们就是1 << 10 ,这个范围来表示该数字含有哪些数字,比如110101 , 含有0 , 2 , 4 , 5 , 如果该数字里面还有个2, 则不影响该二进制数的值,只要 p |= 1 << (a % 10) , 就是该二进制与上一个尾数所表达的内容,并用num[p] ++ 记录一下这种数字的个数
    最后我们就暴力枚举这1 << 10 , 个数, n ^ 2 复杂度,不会超时 ,i , j <= 1 << 10 , 如果i == j了, 那么就表示这个i所代表的数字有num[i] 个, 两两配对, 就是num[i] * (num[i] - 1) , 这个含有重复的,最后除以2 , 如果i & j 存在, 那么就表示这两个含有相同的数字, 那么我们就是直接加上num[i] * num[j] , , 这个也有重复的,最后结果除以2 ,

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll ;
    ll num[11200] ;
    int main()
    {
    	int n ;
    	cin >> n ;
    	for(int i = 1 ;i <= n ;i ++)
    	 {
    	 	ll a ;
    	 	cin >> a ;
    	 	ll p = 0 ;
    	 	while(a)
    	 	 {
    	 	 	p |= 1 << (a % 10) ;
    	 	 	a /= 10 ;
    		 }
    		 num[p] ++ ;
    	 }
    	 ll m = 1 << 10 ; 
    	 ll ans = 0 ;
    	 for(int i = 1 ;i <= m ;i ++)
    	  for(int j = 1 ;j <= m ;j ++)
    	    if(i == j)
    	     ans += num[i] * (num[i] - 1) ;
    	    else if(i & j)
    	     ans += num[i] * num[j] ;
    	printf("%lld
    " , ans / 2) ;
    	return 0 ;
    } 
    
    每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
  • 相关阅读:
    虚函数
    class与struct的区别
    HTTP是什么连接
    长连接与短连接
    多线程的主要优点
    overload、override、overwrite的介绍
    常用的Linux命令
    IO模型——IO多路复用机制
    栈区与堆区的区别
    软链接和硬链接到底有啥区别
  • 原文地址:https://www.cnblogs.com/spnooyseed/p/12870886.html
Copyright © 2011-2022 走看看