1109A - Sasha and a Bit of Relax

本文介绍了一种利用位运算中的亦或操作解决寻找特定配对问题的方法。通过对亦或特性的理解,文章提出了一种有效的算法,用于计算数组中满足特定条件的funnypair数量。该算法使用了动态规划的思想,并通过记录前缀亦或和来优化搜索过程。

A. Sasha and a Bit of Relax

source: codeforces
tag: dp implementation

这道题的重点在于

  • 对亦或位运算(⊕或^)的理解,位运算中,亦或 = 加(不进位) = 减(不借位)。因此变换含有多个⊕符号的式子时,可以把他当成减号/加号来处理。
  • 对于亦或等式变换的能力
  • 对于pref的理解(pref_i就是从a_1一直亦或到a_i的一长串变量相亦或得到的结果)
思路

首先从题目得到:

a_l ⊕ a_(l+1) ⊕ …… ⊕ a_mid = a_(mid+1) ⊕ a_(mid+2) ⊕ …… ⊕ a_r

左边和右边称为一对funny pair,我们的任务是找出输入数组里面有多少对这样的funny pair。

由亦或运算的特性,两边相等,亦或出来的结果为0 (eg. 1⊕1=0),可以得到:

a_l ⊕ a_(l+1) ⊕ …… ⊕ a_r = 0

现在的任务变成了:数组中有多少对数能够取(l,r), 使得r-l+1为偶数且满足上述从l到r亦或和=0的式子。

我们定义

pref_i = a_1 ⊕ a_2 ⊕ …… ⊕ a_i

通过 pref_r ⊕ pref_l-1, 我们可以得到a_l ⊕ a_(l+1) ⊕ …… ⊕ a_r, 因此,只要满足pref_r ⊕ pref_l-1 = 0, 那么即可以得到我们一开始所求的pref_r = pref_l-1

现在的任务变成了:数组中有多少对,能够使r-l+1为偶数且满足pref_r = pref_l-1

实现

先定义变量,n代表输入数组的长度,a[]代表输入数组,x表示pref(下标和当前亦或的a[i]的i相同),cnt是一个二维数组,第一维表示奇偶,第二维表示曾经达到过异或和(pref)为x的次数,res表示统计的funny pair对数(只有在cnt[i%2][x]里面有东西时才会增加,否则只是加0)。

  • 为了满足r-l+1为偶数,我们采取奇偶分治的策略:l-1和r的奇偶必定一样,否则l到r总共不为偶数个,不足成pair。因为为了满足l-1到r为偶数,我们认为l-1和r的奇偶性一致。

  • 我们定义了一个二维数组,第一维长度为2,[0]、[1]分别代表l-1/r为偶、奇。第二维我们取长度为(1<<20)+3 ,都全置为0,代表pref的结果。

  • 如果输入数组中,有相同第一维(l-1/r奇偶性相同,满足偶数项),并且pref结果也相同的不同位置,那么这两个位置之间(不包括[l-1]但包括[r])能够组成一对funny pair,res需要自加上代表他们重合的数字,即cnt[i%2][x]的值(本来的值应该为0,只有在[l-1]给这个cnt[i%2][x]加1之后,在[r]才可能加上非零的值)

  • 代码

var n=readline(); // 读取数组长度n
var a=readline().split(' '); // 读取数组
a=a.slice(0,n); // 将数组长度设为n
var cnt= []; // 初始化cnt数组
cnt.length=2; // cnt数组第一维长度为2
for(var k=0; k<2; k++){
    cnt[k] = []; // cnt数组第二维
    cnt[k].length=(1<<20)+3; // 第二维长度
    cnt[k].fill(0); // 全部置0
}

cnt[1][0]=1; // 给奇数数组的那一边的第一个pref设为1,因为pref_1=1;
var res=0; // res变量用来存储变量
var x=0; // 当前i的pref=0
for(var i=0; i<n; ++i){
    x^=a[i]; // 和数组的第i个元素a[i]的亦或,即前i个元素的亦或和
    res+=cnt[i%2][x]; 
    // x=pref_i,即从0到n所有pref_i的值
    // 如果其中有两个相等的话(即pref_r=pref_l-1),就会被加到res中去
    ++cnt[i%2][x]; // 和这个pref的值相等次数+1
}

print(res);
复制代码

在codeforces的js引擎中,readline()代表输入,print()代表打印。

  • 测试
Input
5
1 2 3 4 5
Output
1
Expected Answer
1

转载于:https://juejin.im/post/5c9b248ae51d453ae4572c7a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值