A matrix
题目大意 : 问每个子矩阵本质不同行的个数和
-
对于每行建出来trie树,每个节点记录下来有哪几行,在一个结点出现几行的前缀一定是一样的,算出贡献,
-
然后将trie树根的叶子节点合并,相当于忽略一行,就是不看前面的行然后算前缀,合并的时候类似线段树合并,set合并的时候启发式一下就行
-
每次暴力算复杂度不对,所以在更新每个节点的set的时候实时维护结果
Code
Show Code
#include <set>
#include <cstdio>
#include <unordered_map>
using namespace std;
const int N = 5e5 + 5;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
return x * f;
}
set<int> s[N];
int n, m, trc, rt;
long long sum, ans;
set<int>::iterator it;
unordered_map<int, int> ch[N];
void Add(int x, int w) {
if (s[x].find(w) != s[x].end()) return;
set<int>::iterator it = s[x].lower_bound(w);
int lt = it == s[x].begin() ? 0 : (--it, *it++);
ans += 1ll * (w - lt) * (n - w + 1);
if (it != s[x].end()) ans -= 1ll * (w - lt) * (n - *it + 1);
s[x].insert(w);
}
void Del(int x) {
int lt = 0;
for (it = s[x].begin(); it != s[x].end(); ++it)
ans -= 1ll * (*it - lt) * (n - *it + 1), lt = *it;
}
void Merge(int &x, int y) {
if (!x) return x = y, void();
if (s[x].size() < s[y].size()) swap(x, y);
for (it = s[y].begin(); it != s[y].end(); ++it) Add(x, *it);
Del(y);
for (auto c : ch[y]) Merge(ch[x][c.first], c.second);
}
int main() {
n = read(); m = read();
for (int i = 1; i <= n; ++i) {
int x = 0;
for (int j = 1; j <= m; ++j) {
int c = read(), &y = ch[x][c];
if (!y) y = ++trc;
Add(y, i); x = y;
}
}
while (m--) {
Del(rt); sum += ans;
int x = rt; rt = 0;
for (auto y : ch[x])
Merge(rt, y.second);
}
printf("%lld
", sum);
return 0;
}
B sequence
题目大意 : 问l到r中有几个区间的与和能被k整除
-
其实挺简单
-
枚举右端点i,建一颗线段树,每个叶子节点维护有多少个j为起点的区间的与和能被k整除
-
对于右端点相同的区间,与和只有log种取值,能被k整除的就区间加一
-
把询问离线下来,在询问l,r的时候,就在更新完右端点为r的时候查询l,r的区间和即可
Code
Show Code
#include <cstdio>
#include <vector>
#include <algorithm>
#define ls (rt << 1)
#define rs (rt << 1 | 1)
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int read(int x = 0, int f = 1, char c = getchar()) {
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1;
for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0';
return x * f;
}
int n, m, k, a[N], p[32][N], c[32], s[32];
ll t[N*4], tag[N*4], ans[N*5];
vector<int> b[N], id[N];
void Pushdown(int rt, int l, int r) {
int mid = l + r >> 1; ll tmp = tag[rt]; tag[rt] = 0;
tag[ls] += tmp; t[ls] += tmp * (mid - l + 1);
tag[rs] += tmp; t[rs] += tmp * (r - mid);
}
void Add(int rt, int l, int r, int x, int y) {
if (x <= l && r <= y) return t[rt] += (r - l + 1), tag[rt]++, void();
if (tag[rt]) Pushdown(rt, l, r);
int mid = l + r >> 1;
if (x <= mid) Add(ls, l, mid, x, y);
if (y > mid) Add(rs, mid+1, r, x, y);
t[rt] = t[ls] + t[rs];
}
ll Ask(int rt, int l, int r, int x, int y) {
if (x <= l && r <= y) return t[rt];
if (tag[rt]) Pushdown(rt, l, r);
int mid = l + r >> 1; ll ans = 0;
if (x <= mid) ans = Ask(ls, l, mid, x, y);
if (y > mid) ans += Ask(rs, mid+1, r, x, y);
return ans;
}
int main() {
n = read(), m = read(), k = read();
for (int i = 1; i <= n; ++i) {
a[i] = read();
for (int j = 0; j < 30; ++j)
p[j][i] = (a[i] >> j & 1) ? p[j][i-1] : i;
}
for (int i = 1; i <= m; ++i) {
int l = read(), r = read();
b[r].push_back(l); id[r].push_back(i);
}
for (int i = 1; i <= n; ++i) {
for (int j = 0; j < 30; ++j)
s[j] = p[j][i];
int sum = (1 << 30) - 1, lt = i; sort(s, s + 30);
for (int j = 29; j >= 0 && s[j]; --j) {
if (s[j] == s[j+1]) continue;
if (sum % k == 0) Add(1, 1, n, s[j] + 1, lt);
sum &= a[s[j]]; lt = s[j];
}
if (sum % k == 0) Add(1, 1, n, 1, lt);
for (int j = 0; j < b[i].size(); ++j)
ans[id[i][j]] = Ask(1, 1, n, b[i][j], i);
}
for (int i = 1; i <= m; ++i)
printf("%lld
", ans[i]);
return 0;
}
C permutation (Unaccepted)
题目大意 :
Code
Show Code