noi online2021
T1
智力康复中,先放着……
T2
考场上算错空间炸无了……
首先可以枚举第二个串的每个字串
把合法(贪心判断)的插入字典树去重
然后输出节点个数就行了
空间要动态开(可以用邻接链表)
#include<bits/stdc++.h>
#define N 9000050
using namespace std;
struct edge {
int v, nxt, c;
} e[N << 1];
int p[N << 1], eid;
void init() {
memset(p, -1, sizeof p);
eid = 0;
}
void add(int u, int v, int c) { //printf("%d ---> %d %d\n", u, v, c);
e[eid].v = v;
e[eid].c = c;
e[eid].nxt = p[u];
p[u] = eid ++;
}
int n, sz, tot, ch[N << 1];
char st[N], stt[N];
int insert(int l, int r) { //printf("%d %d %d\n", l, r, tot);
int x = 0;
for(int i = l; i <= r; i ++) {
int c = stt[i] - 'a', ff = 0;
for(int j = p[x]; j + 1; j = e[j].nxt) {
int v = e[j].v, cc = e[j].c;
if(cc == c) {
ff = 1, x = v; break;
}
}
if(!ff) ++ tot, add(x, tot, c), x = tot;
}
}
int main() {
init();
scanf("%d", &n);
scanf("%s", st + 1), scanf("%s", stt + 1);
for(int i = 1; i <= n; i ++) {
int p = 1, ha = 0, haa = 0;
for(int j = i; j <= n + 1; j ++) {
while(p <= n && st[p] != stt[j]) p ++;
if(p > n) {
insert(i, j - 1);
break;
} p ++;
}
}
printf("%d", tot);
return 0;
}
/*
3
aaa
aaa
*/
T3
这题好好玩!
先不考虑区间限制
首先肯定是分两种情况讨论
1、对于
b
<
d
b<d
b<d的,
(
a
⊕
c
)
≤
d
(a\oplus c) \leq d
(a⊕c)≤d,这种情况可以直接把
a
a
a全部拉出来建个字典树,然后把
(
c
,
d
)
(c,d)
(c,d)放上去跑,统计个数
2、对于
b
>
d
b>d
b>d的,
(
a
⊕
c
)
≤
b
(a\oplus c) \leq b
(a⊕c)≤b,发现和上一个操作是反过来的(感性理解),可以把所有的c拉出来,建个字典树,然后考虑每对
a
,
b
a,b
a,b对
c
c
c的贡献(在字典树上打标记),然后直接拿d在字典树上跑一遍就行了
现在考虑区间限制,因为是统计个数,所以具有可加性和可减性,直接利用可加性把区间拆分成log个区间丢到线段树上(线段树分治),然后每个区间把 b , d b,d b,d分别排序,对于 b < d , b > d b<d,b>d b<d,b>d的用不同的两颗字典树维护就行了,具体看代码吧
#include<bits/stdc++.h>
#define N 400005
using namespace std;
vector<int> t[N << 2];
int a[N], b[N], c[N], d[N], n, m, ans[N], id[N];
void chai(int rt, int l, int r, int L, int R, int id) {
if(L <= l && r <= R) { t[rt].push_back(id); return;}
int mid = (l + r) >> 1;
if(L <= mid) chai(rt << 1, l, mid, L, R, id);
if(R > mid) chai(rt << 1 | 1, mid + 1, r, L, R, id);
}
struct TIREA {
int tot, ch[N*25][2], size[N * 25];
void clear() {
for(int i = 0; i <= tot; i ++) ch[i][0] = ch[i][1] = size[i] = 0;
tot = 1;
}
void insert(int x, int o) {
int p = 1; size[p] += o;
for(int i = 24; i >= 0; i --) {
int c = (x >> i) & 1;
if(!ch[p][c]) ch[p][c] = ++ tot;
p = ch[p][c]; size[p] += o;
}
}
int query(int p, int c, int d, int k) {
if(!p) return 0;
if(k == -1) return size[p];
int cv = (c >> k) & 1, dv = (d >> k) & 1;
if(dv == 0) return query(ch[p][cv], c, d, k - 1);
return size[ch[p][cv]] + query(ch[p][cv ^ 1], c, d, k - 1);
}
} A;
struct TIREB {
int tot, ch[N*25][2], size[N * 25];
void clear() {
for(int i = 0; i <= tot; i ++) ch[i][0] = ch[i][1] = size[i] = 0;
tot = 1;
}
int query(int x) {
int p = 1, ret = 0;
for(int i = 24; i >= 0; i --) {
int c = (x >> i) & 1;
p = ch[p][c]; ret += size[p];
if(!p) break;
}
return ret;
}
void insert(int p, int a, int b, int k) {
if(!p) return ;
if(k == -1) {size[p] ++; return ;}
if(!ch[p][0]) ch[p][0] = ++ tot;
if(!ch[p][1]) ch[p][1] = ++ tot;
int av = (a >> k) & 1, bv = (b >> k) & 1;
if(bv == 0) insert(ch[p][av], a, b, k - 1);
else size[ch[p][av]] ++,insert(ch[p][av ^ 1], a, b, k - 1);
}
} B;
int cmp(int x, int y) {
return d[x] < d[y];
}
int cmpp(int x, int y) {
return b[x] < b[y];
}
void solve(int rt, int l, int r) {
A.clear(), B.clear();
sort(t[rt].begin(), t[rt].end(), cmp);
for(int i = l; i <= r; i ++) id[i] = i, A.insert(a[i], 1);;
sort(id + l, id + r + 1, cmpp);
int pos = l;
for(int i = 0; i < t[rt].size(); i ++) {
int u = t[rt][i];
while(d[u] >= b[id[pos]] && pos <= r) A.insert(a[id[pos]], -1), B.insert(1, a[id[pos]], b[id[pos]], 24), pos ++;
ans[u] += A.query(1, c[u], d[u], 24) + B.query(c[u]);
}
if(l == r) return;
int mid = (l + r) >> 1;
solve(rt << 1, l, mid), solve(rt << 1 | 1, mid + 1, r);
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d%d", &a[i], &b[i]);
for(int i = 1; i <= m; i ++) {
int l, r;
scanf("%d%d%d%d", &l, &r, &c[i], &d[i]);
chai(1, 1, n, l, r, i);
}
solve(1, 1, n);
for(int i = 1; i <= m; i ++) printf("%d\n", ans[i]);
return 0;
}
代码能力还有思维速度,比赛状态还没有回复,只能靠刷题和多打比赛回复了,知识点就先复习吧,暂时不要学新的了