题解 P8055 B Highbit & lowbit
Suzt_ilymtics · · 题解
update on 2022/03/16: 感谢 @Clarence_Zhu 指出一处手误的地方。
题面传送w
Solution
Subtask1
模拟。
复杂度
Subtask2
记录位数模拟。
复杂度
Subtask3
观察操作
那每次操作一定是把最高位
所以每次询问的答案为
Subtask5
4 没写
发现如果整个数在二进制位上只有一位是
然后这个和 Subtask3 的答案是相同的。
正解
考虑两个操作的本质,
如果最高位的
设两个位置之间有
考虑什么时候出现这种情况?在某个位置
设
设找到的位置为
并且这个位置应该是我们遇到的第一个满足这样条件的
发现其中有两项是常量,设
式子变为:
我们可以用值域 vector 存下每个 lower_bound 一下找到第一个满足条件的
如果能找到一个合法的
如果找不到的话,分两种情况讨论。
设
如果 x+=lowbit(x),复杂度只有
如果
然后这题就做完了,复杂度应该是
Code
/*
Work by: Suzt_ilymtics
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define int long long
#define orz cout<<"lkp AK IOI!"<<endl
using namespace std;
const int MAXN = 2e6+5;
const int INF = 1e9+7;
const int mod = 1e9+7;
int n, Q;
int a[MAXN], sum[2][MAXN];
vector<int> b[MAXN];
int read() {
int s = 0, f = 0;
char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
return f ? -s : s;
}
int Getl(int x) { for(int i = 0; i <= 40; ++i) if(x & (1ll << i)) return i; }
int Getr(int x) { for(int i = 40; i >= 0; --i) if(x & (1ll << i)) return i; }
int lb(int x) { return x & (-x); }
int Pow(int x, int p) {
int res = 1;
while(p) {
if(p & 1) res = res * x % mod;
x = x * x % mod, p >>= 1;
}
return res;
}
signed main()
{
n = read(), Q = read();
for(int i = 1; i <= n; ++i) scanf("%1d", &a[i]);
for(int i = 1; i <= n; ++i)
sum[0][i] = sum[0][i - 1] + (a[i] == 0), sum[1][i] = sum[1][i - 1] + (a[i] == 1);
int M = 100000;
for(int i = 1; i <= n; ++i) b[M + sum[0][i] - sum[1][i]].push_back(i); // 用值域 vector 预处理一下位置
for(int i = -M; i <= M; ++i) b[i + M].push_back(n + 1); // 每个值域都放一个 vector 方便判断有无解(其实我就是忘了 vector 用 lower_bound 找不到一个数是返回什么值)
for(int i = 1, l, r, x; i <= Q; ++i) {
l = read(), r = read(), x = read();
int L = Getl(x), R = Getr(x), k = 0;
if(L == R) { // Subtask5
printf("%lld\n", Pow(2, L + r - l + 1));
} else {
++k;
for(int j = L; j <= R; ++j) if(!(x & (1ll << j))) ++k;
k = M + k + sum[0][l - 1] - sum[1][l - 1];
int p = lower_bound(b[k].begin(), b[k].end(), l) - b[k].begin();
if(b[k][p] > r) {
int s0 = sum[0][r] - sum[0][l - 1], s1 = sum[1][r] - sum[1][l - 1];
k = k - M - sum[0][l - 1] + sum[1][l - 1];
if(s0 < k) { // 无解下的情况 1
int ans = Pow(2, R + s1);
x -= (1ll << R);
while(s0--) x += lb(x);
ans = (ans + x) % mod;
printf("%lld\n", ans);
} else { // 无解下的情况 2
int ans = (Pow(2, R + s0 - k) + Pow(2, R + s1)) % mod;
printf("%lld\n", ans);
}
} else { // 有解的情况
p = b[k][p];
printf("%lld\n", Pow(2, R + sum[1][p] - sum[1][l - 1] + 1 + (r - p)));
}
}
}
return 0;
}