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 (ac)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 (ac)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;
}

代码能力还有思维速度,比赛状态还没有回复,只能靠刷题和多打比赛回复了,知识点就先复习吧,暂时不要学新的了

posted @ 2021-03-30 21:30  lahlah  阅读(37)  评论(0编辑  收藏  举报