作业介绍

// s 当前要插入的字符串
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6 + 10;
int T, n, m;
// trie[节点个数][每个节点最多能拓展出几条边]
// 大写字母(26),小写字母(26), 数字(10)
int trie[N][65], cnt;
int sum[N];

int get(char c) {
	if (c >= 'A' && c <= 'Z')
		return c - 'A';
	if (c >= 'a' && c <= 'z')
		return c - 'a' + 26;
	return  c - '0' + 52;
}

// l 字符串 s 的长度
void insert(string s) {  // 插入字符串
	int l = s.size();
	int p = 0;
	for (int i = 0; i < l; i++) {
		int c = get(s[i]);
		if (!trie[p][c])
			trie[p][c] = ++cnt;  // 如果没有,就添加结点
		p = trie[p][c];
		sum[p]++; // 经过这点的字符串的数量增加
	}
}

int find(string s) {  // 查找字符串
	int p = 0, l = s.size();
	int res = 0;
	for (int i = 0; i < l; i++) {
		int c = get(s[i]);
		if (!trie[p][c])
			return 0;
		p = trie[p][c];
		// 查找 s 的时候经过 p 点,那么p 点 可能 是 s 的前缀
	}
	return sum[p];
}

int main() {
	cin >> T;
	while (T--) {
		cin >> n >> m;
		for (int i = 0; i <= cnt; i++) {
			sum[i] = 0;
			for (int j = 0; j <= 62; j++)
				trie[i][j] = 0;
		}
		cnt = 0;
		for (int i = 1; i <= n; i++) {
			string s;
			cin >> s;
			insert(s);
		}
		for (int i = 1; i <= m; i++) {
			string s;
			cin >> s;
			cout << find(s) << endl;
		}
	}
	return 0;
}
// n 条二进制信息,每条长度 b[i],
// m 条查询密码,每条长度 c[j]
// 对于每条密码,统计有多少条信息满足:两者前 min(b[i],c[j]) 位完全相同
// 二进制 trie 前缀树
// pass[p] , 有多少条信息经过节点 p ,
// ed[p] 有多少条信息在节点 p 结束

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+10;
int trie[N][2], pass[N], ed[N], idx;
int a[N], n, m;

void insert(int len, int a[]) {
	int p = 0;
	for (int i = 0; i < len; i++) {
		int c = a[i];
		if (!trie[p][c])
			trie[p][c] = ++idx;
		p = trie[p][c];
		pass[p]++;  // 经过该节点的字符串个数
	}
	ed[p]++;  // 以该字符结尾的个数
}

int query(int len, int a[]) {
	int p = 0, res = 0;
	for (int i = 0; i < len; i++) {
		int c  = a[i];
		if (!trie[p][c])
			return res;
		p = trie[p][c];
		res += ed[p]; // 加上与当前节点为结束的个数
	}
	// 加上前缀相同且长度比它长的字符串个数
	return res - ed[p] + pass[p];
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		int len;
		cin >> len;
		for (int j = 0; j < len; j++)
			cin >> a[j];
		insert(len, a);
	}
	while (m--) {
		int len;
		cin >> len;
		for (int j = 0; j < len; j++)
			cin >> a[j];
		cout << query(len, a) << endl;
	}
	return 0;
}
异或: 相同为 0 不同为 1
//建字典树:第一个数直接建字典树
//
//从第二个数字开始,
//建立字典树的时候,如果有相反的边,走这条边
//  对应的这一个位, 值就是 1
//如果没有相反的边, 这一位 就是 0
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int trie[N * 32][2], idx;


void insert() {
	// ...
}

int query(int x) {
	int p = 0, res = 0;
	for (int i = 30 ; i >= 0; i--) {
		int u = x >> i & 1; // 得到第 x 位的值
		if (trie[p][!u])  // 优先走相反的位
			res |= 1 << i, p = trie[p][!u];
		else
			p = trie[p][u];
	}
	return res;
}


int main() {
	cin >> n;
	int ans = 0;
	for (int i = 1; i <= n; i++) {
		cin >> x;
		if (x > 1)
			ans = max(ans, query(x));
		insert(x);
	}
	cout << ans;
	return 0;
}
// 字典,
// 字符串,问你在字典里面,
// 字符串最多能翻译到多少
// trie + DP
// f[i] : 能翻译到 i
// 状态转移: f[i] = |f[j]  [j+1, i]之间有单词
// [j+1, i]之间有单词  字典树 ,ed[i]
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int trie[N][26], idx;
int n, m, f[N];
bool ed[N];

void insert(string s) {
	int p = 0, len = s.size();
	for (int i = 0; i < len; i++) {
		int u = s[i] - 'a';
		if (!trie[p][u])
			trie[p][u] = ++idx;
		p = trie[p][u];
	}
	ed[p] = 1;
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		string s;
		cin >> s;
		insert(s);
	}
	while (m--) {
		string s;
		cin >> s;
		int len = s.size();
		memset(f, 0, sizeof f);
		f[0] = 1;
		int ans = 0;
		//  f[i] = |f[j]  [j+1, i]之间有单词
		for (int i = 0; i <= len; i++) {
			if (!f[i])
				continue;
			ans = i ;
			int p = 0 ;
			for (int k = i; k < min(len, i + 20) ; k++) {
				int u = s[k] - 'a';
				if (!trie[p][u])
					break;
				p = trie[p][u];
				if (ed[p])
					f[k + 1] = 1;
			}
		}
		cout << ans << endl;
	}
	return 0;
}
// 字典树:带着信息
// cnt[p] 到达某个点的数量/是否到达
// ed[p] 以某个点结束的数量/是否到达
// 两个字符串的相同前缀, a 和 b 的前缀
// a 的长度小于 b , b 的长度小于 a 
// query(b)
// a 的长度小于 b  : sum(ed(p)) , a的路径上
//  1110         1110
//  11100000     11010

// b 的长度小于 a 
// 1101110   11001010  1100000
// 110   经过 0 的数量
// sum[p] 统计经过 p 的数量 , ed[p] 以 p结尾的数量

int trie[N][2], sum[N], ed[N],idx;
int n,m;

void insert(int len, int a[]){
	int p =0;
	for(int i=0;i<len;i++){
		int u = a[i];
		if(!trie[p][u])
			trie[p][u] = ++idx;
		p = trie[p][u];
		sum[p]++;  // 经过这个点的数量
	}
	ed[p]++;  // 以这个点结束的数量
}

int query(int len, int a[]){
	int p =0, res =0;
	for(int i=0;i<len;i++){
		int u = a[i];
		if(!trie[p][u])
			return res;
		p = trie[p][u];
		res += ed[p];
	}
	// 累加的是比 a 长的编码的
	res = res + sum[p] - ed[p];
}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int T, n;
int trie[N][10], idx;
bool ed[N]; // 标记是否以这个结尾
bool flg;

void insert(string s) {
	int p = 0, l = s.size();
	for (int i = 0; i < l; i++) {
		int u = s[i] - '0';
		if (!trie[p][u])
			trie[p][u] = ++idx;
		else if (i == l - 1 && !flg)   // 后输入的字符串是之前输入的字符串的前缀
			flg = 1;
		p = trie[p][u];
		if (ed[p])  // 之前输入的字符串是现在的字符串的前缀
			flg = 1;
	}
	ed[p] = 1;
}

int main() {
	cin >> T;
	while (T--) {
		cin >> n;
		flg = idx = 0;
		memset(trie, 0, sizeof trie);
		memset(ed, 0, sizeof ed);
		for (int i = 1; i <= n; i++) {
			string s;
			cin >> s;
			if (flg)
				continue;
			insert(s);
		}
		if (flg)
			cout << "NO\n";
		else
			cout << "YES\n";
	}
	return 0;
}

题目

认领作业后才可以查看作业内容。
状态
正在进行…
题目
7
开始时间
2026-10-1 0:00
截止时间
2026-10-31 23:59
可延期
24 小时