51nod NOI科目校 信息学知识点测评-普及组综合测试 C 数对(非正解,但没有被卡掉)

原题链接

C 数对

题目大意

定义 A n d And And 为按位与操作, X o r Xor Xor 为按位异或操作。
给一个包含 n n n 个元素的正整数序列 a a a,计算满足 a i   A n d   a j ≥ a i   X o r   a j a_i\ And\ a_j≥a_i\ Xor \ a_j ai And ajai Xor aj ( i , j ) (i,j) (i,j)     ( i < j ) \ \ \ (i<j)    (i<j) 的数对数量。

解题思路

对于本蒟蒻来讲,这题还挺数学。
先了解一下 A n d And And 的性质: a   A n d   b ≤ m i n ( a , b ) a\ And\ b\le min(a,b) a And bmin(a,b)请记住,这很重要
现在再来看 X o r Xor Xor 的性质,由于位运算不够位数回自动补0,当出现两数 a , b a,b a,b 时:
⌊ log ⁡ 2 a ⌋ ≠ ⌊ log ⁡ 2 b ⌋ \left \lfloor \log_2a \right \rfloor \ne \left \lfloor \log_2b \right \rfloor log2a=log2b(两数的二进制长度不相等),
⌊ log ⁡ 2 ( a   X o r   b ) ⌋ = max ⁡ ( ⌊ log ⁡ 2 a ⌋ , ⌊ log ⁡ 2 b ⌋ ) \left \lfloor \log_2(a\ Xor\ b) \right \rfloor =\max(\left \lfloor \log_2a \right \rfloor ,\left \lfloor \log_2b \right \rfloor) log2(a Xor b)=max(log2a,log2b)(因为较短的数会自动补0)
⌊ log ⁡ 2 a ⌋ = ⌊ log ⁡ 2 b ⌋ \left \lfloor \log_2a \right \rfloor=\left \lfloor \log_2b \right \rfloor log2a=log2b(两数的二进制长度不相等),
⌊ log ⁡ 2 ( a   X o r   b ) ⌋ < log ⁡ 2 a , ⌊ log ⁡ 2 ( a   X o r   b ) ⌋ < log ⁡ 2 b \left \lfloor \log_2(a\ Xor\ b) \right \rfloor <\log_2a,\left \lfloor \log_2(a\ Xor\ b) \right \rfloor <\log_2b log2(a Xor b)<log2a,log2(a Xor b)<log2b(因为第一位会变成0)
也就是说: a   X o r   b < min ⁡ ( a , b ) a\ Xor\ b< \min(a,b) a Xor b<min(a,b)
联系上文 a   A n d   b ≤ m i n ( a , b ) a\ And\ b\le min(a,b) a And bmin(a,b) 我们可以发现,只有当 ⌊ log ⁡ 2 a ⌋ = ⌊ log ⁡ 2 b ⌋ \left \lfloor \log_2a \right \rfloor=\left \lfloor \log_2b \right \rfloor log2a=log2b 时, a   A n d   b ≤ a   X o r   b a\ And\ b\le a\ Xor\ b a And ba Xor b 才有可能实现。于是,我们可以将数列中的数按照二进制长度分类,再在每一类别中进行枚举,答案便出来了!
非正解,若 a a a 中所有的数以二为底的对数都一样,会被卡掉!

代码实现

#include<bits/stdc++.h>
using namespace std;
int t,f[10010],a[10010],Log2_of_a[10010],n;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>t;
	for(int i=1;i<=t;i++){
		cin>>n;
		int Max_a=0;
		vector<int> Log_2[10010];
		for(int j=1;j<=n;j++){
			cin>>a[j];
			Max_a=max(Max_a,a[j]);
			Log2_of_a[j]=floor(log2(a[j]));
			Log_2[Log2_of_a[j]].push_back(j);
		}
		int ans=0;
		for(int j=1;j<=n;j++){
			int log2a=Log2_of_a[j];
			for(int k=0;k<Log_2[log2a].size();k++){
				if(Log_2[log2a][k]!=j&&j<Log_2[log2a][k]){
					if((a[j]&a[Log_2[log2a][k]])>=(a[j]^a[Log_2[log2a][k]]))
						ans++;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值