@51nod - 1577@ 异或凑数


@description@

从左到右一共 n 个数,数字下标从 1 到 n 编号。

一共 m 次询问,每次询问是否能从第 L 个到第 R 个数中(包括第 L 个和第 R 个数)选出一些数使得他们异或为 K。

input
第一行一个整数 n (0<n<=500,000)。
第二行 n 个整数,0<每个数<2^30。
第三行一个数 m,表示询问次数 (0<m<=500,000)。
接下来 m 行每行三个数,L, R, K (0<L<=R<=n,0<K<2^30)。

output
M 行,每行为 YES 或 NO

sample input
5
1 1 2 4 6
3
1 2 1
2 4 8
3 5 7
sample output
YES
NO
NO

@solution@

能否选出一些数使这些数的异或和为 K。不难想到使用线性基来解决。

如果在题目给定的数据范围下想要直接构造出区间 [L, R] 的线性基实际上并不容易。
带根号的比如莫队、分块肯定跑不动。在线使用线段树 O(nlog^3 n),离线用分治可以做到 O(nlog^2 n),能过一些点但是仍然不够优秀。
关键在于我们想要构造出 [L, R] 的线性基,涉及到会合并两个线性基的操作,而这个操作复杂度始终是 log^2 n 降不下来。

不妨换个角度:我们给定 R 与 K,可以发现 L 越往左能异或出的值越多。于是我们可以尝试去找第一个可以异或出 K 的 L',然后再比较 L 与 L' 的大小判断合法性。
我们尝试对于每一个 R 维护出最靠近 R 的若干线性无关的数构成的线性基。这个思路类似于 bzoj3514 的解题思路。

具体操作来说,我们从左往右扫,由 R-1 的线性基递推出 R 的线性基。
我们在线性基从高位往低位。如果当前的数在第 i 位为 1,再看线性基的第 i 位是否已经有数了。如果没有数则直接放进去,如果有数则比较当前的数和线性基里的数哪一个更靠近 R,将更靠近的放入线性基,另一个继续执行插入操作。
有点像冒泡排序,更靠近的 R 的数将其他数挤了出去。

同时,我们可以发现线性基中的高位取了尽量靠近 R 的数。
所以当我们尝试异或出 K 时,如果遇到某一位的数的位置小于 L,并且这一位数是我们在异或出 K 时所需要的,可以直接判定为“NO”。
说实话这里严格证明起来很麻烦。我能力有限,无法找到一个较为简洁的该算法正确性证明。
毕竟线性基也是线性代数啊。怎么可能会很简单。

@accepted code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 500000;
int read() {
    int x = 0; char ch = getchar();
    while( ch > '9' || ch < '0' ) ch = getchar();
    while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
    return x;
}
void insert(int *pos, int *b, int x, int p) {
    for(int i=29;i>=0;i--) {
        if( x & (1<<i) ) {
            if( b[i] == 0 ) {
                b[i] = x;
                pos[i] = p;
            }
            else if( pos[i] < p ) {
                swap(pos[i], p);
                swap(b[i], x);
            }
            x ^= b[i];
        }
    }
}
bool search(int *pos, int *b, int x, int p) {
    for(int i=29;i>=0;i--) {
        if( x & (1<<i) ) {
            if( b[i] == 0 || pos[i] < p )
                return false;
            x ^= b[i];
        }
    }
    return true;
}
int pos[MAXN + 5][30], b[MAXN + 5][30];
int main() {
    int n, m; n = read();
    for(int i=1;i<=n;i++) {
        int x = read();
        for(int j=29;j>=0;j--)
            pos[i][j] = pos[i-1][j], b[i][j] = b[i-1][j];
        insert(pos[i], b[i], x, i);
    }
    m = read();
    for(int i=1;i<=m;i++) {
        int L = read(), R = read(), K = read();
        puts(search(pos[R], b[R], K, L) ? "YES" : "NO");
    }
}

@details@

好久没复习线性基了。。。写这个题的时候搞出了一个假的线性基。。。于是 WA 的很惨烈。。。

线性基的插入可以类比为动态加入方程的高斯消元。不过因为我们需要构造出特殊的线性基(即要求线性基的第 i 位的数二进制下最高位的 1 在第 i 位。。。好像有些绕口),所以写高斯消元无法满足这些性质。
另外线性基还可以再特殊一点(类比高斯消元化至最简形式),即要求线性基第 i 位上如果有数,则其他位置的二进制下第 i 位上为 0。

好像很多人都是离线做的,不过这道题可以通过存储每个位置的线性基做到在线来着。

转载于:https://www.cnblogs.com/Tiw-Air-OAO/p/11123375.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如择性搜索)来生成候框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候框输入到另一个 CNN 中进行分类,并根据分类结果对候框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑。NMS称为非极大值抑制,作用是从众多预测边界框中挑出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值