2 条题解
-
2
做之前:有点囊啊…………
做之后:🍭超甜题扫一遍就过了,折半在哪?正题
先看题目,,先考虑的大暴力骗分.
#include<bits/stdc++.h> #define int long long using namespace std; int n,a[5005],ans; signed main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ for(int p=j+1;p<=n;p++){ for(int k=p+1;k<=n;k++){ if((a[i]^a[j]^a[p]^a[k])==0){ ans++; } } } } } cout<<ans; return 0; }but……,just 20pts……
所以考虑优化……优化
很明显故可过,那我们怎么搞呢?
注意到,,我们把扔进计算器得到,那位运算的答案就很有限了
故再用计算器算一下可知$a_{b_1}\oplus a_{b_2}\oplus a_{b_3}\oplus a_{b_4}\le 11111111111111111111_2=1048575$.也就是说我们可以用一个桶排计数,把某个下标之前的个数的异或结果.
那应该取多少呢?(都是折半了,当然取2了)那么为什么取呢???
我们容易想到,枚举~的所有二元组满足的做法,即以下两段:
for(int i=2;i<=n;i++){ for(int j=1;j<i;j++){ //其中(j,i)为满足条件的所有情况 } }以及
for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ //其中(i,j)为满足条件的所有情况 } }那我们如何引入这道题呢,我们想:以两个下标为界,分别枚举~和~两个区间内的所有满足上述条件的二元组,则可以保证找出的四个下标绝对满足,若其对应数组中值的异或值为0,就是一个满足的答案.
因此有以下结论:- 对于~范围内求出的二元组,对区间至到的各个区间的结果都是可做出合法贡献的.
- 对于两个数若,则
因此我们有了桶排计数的基础,每当枚举区间~,将的值累加入桶,然后再枚举区间~,其中的累加值为对应的桶中的累加值,那答案就很显而易见了.
对于其时间复杂度:为双层循环嵌套,易知复杂度为
//这么简单的Code不会还要注释吧 #include<bits/stdc++.h> #define int long long using namespace std; const int N=5e6+5; int n,a[5005],ans; int t[N]; signed main() { ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } //下标为什么从这开始自己想 for(int i=2;i<=n-2;i++){ for(int j=1;j<i;j++){ t[a[i]^a[j]]++; } for(int j=i+2;j<=n;j++){ ans+=t[a[i+1]^a[j]]; } } cout<<ans; return 0; }最后不要忘了:十年OI一场空,_____________
- 1
信息
- ID
- 1007
- 提交时间
- 1000ms
- 内存
- 128MiB
- 难度
- 4
- 标签
- 递交数
- 10
- 已通过
- 2
- 上传者
冀公网安备13098402000493号