[NBUT 1646 Internet of Lights and Switches] 前缀异或和+二分

这篇博客介绍了如何利用前缀异或和结合二分搜索算法来解决NBUT 1646互联网灯光和开关问题。通过这种技术,可以高效地处理大量灯具的状态切换,并实现有效的查询优化。
摘要由CSDN通过智能技术生成

[NBUT 1646 Internet of Lights and Switches] 前缀异或和+二分

题意描述:N 个灯, M 个开关,每个开关可以控制多个灯。每个开关对应一个01串,第 i 位为0 表示 这个开关不能控制第i 盏灯, 为1 表示能够控制。初始灯是全亮的。你可以按一个连续区间的开关使得灯全灭,区间的长度必须是在[a, b],问 有多少种 方法可以使灯全灭。每个开关只能按一次。
解题思路:显然,按区间[L, R] 的开关等价于 先按一次[1, L - 1],  然后再按一次[L, R] 区间的开关。所以我们首先需要处理出前 i 盏灯的 前缀异或和, 用pre[] 表示。 要让灯全灭, 就相当于找出区间[L, R], 满足 这个区间 的异或和全为1。 也就等价于pre[R] ^ pre[L - 1] 全1。知道这个就简单很多了。我们只需要枚举区间左端点,然后二分区间右端点。然后求出区间长度就OK了。
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

//#pragma comment(linker, "/STACK:1024000000,1024000000")

#define FIN             freopen("input.txt","r",stdin)
#define FOUT            freopen("output.txt","w",stdout)
#define fst             first
#define snd             second

typedef __int64  LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;

const double eps = 1e-10;

const int MAXN = 50 + 5;
const int MAXM = 300000 + 5;
const int INF  = 0x3f3f3f3f;

int T, N, M, A, B;
char buf[MAXN];
LL pre[MAXM], X, Y, E;
PLL data[MAXM];
LL F (char s[]) {
    LL ret = 0LL;
    for (int i = 0; s[i]; i++) {
        ret = (ret << 1) + s[i] - '0';
    }
    return ret;
}
int main() {
#ifndef ONLINE_JUDGE
    FIN;
//     FOUT;
#endif // ONLINE_JUDGE
    int cas = 0;
    LL res;
    while (~scanf ("%d %d %d %d", &N, &M, &A, &B) ) {
        res = E = pre[0] = 0LL;
        for (int i = 1; i <= N; i++) {
            E = (E << 1) | 1;
        }
        data[0] = PLL (0, 0);
        for (int i = 1; i <= M; i++) {
            scanf ("%s", buf);
            X = F (buf);
            pre[i] = pre[i - 1] ^ X;
            data[i].fst = pre[i];
            data[i].snd = i;
        }
        sort (data, data + M + 1);
        for (int i = 0; i <= M; i++) {
            X = data[i].fst;
            Y = data[i].snd;
            int a = lower_bound (data + 1, data + M + 1, PLL (X ^ E, Y + A) ) - data;
            int b = upper_bound (data + 1, data + M + 1, PLL (X ^ E, Y + B) ) - data;
            if (a > M) continue;
            res += (b - a);
        }
        printf ("Case %d: %I64d\n", ++cas, res);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值