Trie
又是一个很久没用过的东西。
随便找了个Trie的题结果发现是这样的:P5149 会议座位
看完题目完全没有想到Trie,这不是很明显的map+归并排序吗
所以可以这样做
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 9;
template <typename T>
inline void read(T &x)
{
T data = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
data = (data << 3) + (data << 1) + ch - '0';
ch = getchar();
}
x = f * data;
}
map<string, int> mp;
int n[maxn], tmp[maxn];
string s;
ll ans = 0;
void msort(int l, int r)
{
if (l >= r)
return;
int mid = l + r >> 1;
msort(l, mid);
msort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while (i <= mid && j <= r)
{
if (n[i] < n[j])
tmp[k++] = n[i++];
else
tmp[k++] = n[j++], ans += mid - i + 1;
}
while (i <= mid)
tmp[k++] = n[i++];
while (j <= r)
tmp[k++] = n[j++];
for (int i = l; i <= r; ++i)
n[i] = tmp[i];
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("data.txt","w",stdout);
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
int T;
cin >> T;
for (int i = 1; i <= T; ++i)
{
cin >> s;
mp[s] = i;
}
for (int i = 1; i <= T; ++i)
{
cin >> s;
n[mp[s]] = i;
}
msort(1, T);
cout << ans << '\n';
//fclose(stdin);
//fclose(stdout);
return 0;
}
树状数组好像也可以求逆序对个数但是慢,处理相同元素复杂,还没有归并排序好写。
然后试着用Trie做一下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5 + 9;
template <typename T>
inline void read(T &x)
{
T data = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
data = (data << 3) + (data << 1) + ch - '0';
ch = getchar();
}
x = f * data;
}
int n[maxn], tmp[maxn];
string s;
ll ans = 0;
void msort(int l, int r)
{
if (l >= r)
return;
int mid = l + r >> 1;
msort(l, mid);
msort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while (i <= mid && j <= r)
{
if (n[i] < n[j])
tmp[k++] = n[i++];
else
tmp[k++] = n[j++], ans += mid - i + 1;
}
while (i <= mid)
tmp[k++] = n[i++];
while (j <= r)
tmp[k++] = n[j++];
for (int i = l; i <= r; ++i)
n[i] = tmp[i];
}
struct node
{
int cnt, word;
int son[52];
node()
{
cnt = word = 0;
memset(son, 0, sizeof(son));
}
};
node trie[5 * maxn];
int num = 0;
void ins(string &s, int n)
{
int t, len = s.length(), pos = 0;
for (int i = 0; i < len; ++i)
{
if ('a' <= s[i] && 'z' >= s[i])
t = (int)s[i] - 'a';
else
t = (int)s[i] - 'A' + 26;
if (trie[pos].son[t] == 0)
trie[pos].son[t] = ++num;
pos = trie[pos].son[t];
}
trie[pos].word = n;
}
int check(string &s)
{
int t, len = s.length(), pos = 0;
for (int i = 0; i < len; ++i)
{
if ('a' <= s[i] && 'z' >= s[i])
t = (int)s[i] - 'a';
else
t = (int)s[i] - 'A' + 26;
pos = trie[pos].son[t];
}
return trie[pos].word;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("data.txt","w",stdout);
//std::ios::sync_with_stdio(false);
//std::cin.tie(0);
int T;
cin >> T;
for (int i = 1; i <= T; ++i)
{
cin >> s;
ins(s, i);
}
for (int i = 1; i <= T; ++i)
{
cin >> s;
n[check(s)] = i;
}
msort(1, T);
cout << ans << '\n';
//fclose(stdin);
//fclose(stdout);
return 0;
}
数组开的提心吊胆,虽然用Trie的代码比用map的快了一些(数据少的时候map快,数据非常多的时候map的用时大约是Trie的1.5倍),但是Trie的空间开销超过了map的10倍。。。
KMP
已经忘的差不多了。大概是先预处理模式串,构建一个next数组记录模式串的某个前缀的真前缀与真后缀相同的位置,然后匹配时如果中断了就把之前一段的有效后缀直接作为前缀拿来用(长度已经在next数组里标好了)。KMP算法匹配的时候头指针不会回跳,所以复杂度是 O ( n + k ) O(n+k) O(n+k)。
P2375 [NOI2014]动物园 求出KMP的next数组后做一些处理即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 9;
template <typename T>
inline void read(T &x)
{
T data = 0, nxt = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')
nxt = -1;
ch = getchar();
}
while (isdigit(ch))
{
data = (data << 3) + (data << 1) + ch - '0';
ch = getchar();
}
x = nxt * data;
}
const ull mod = 1e9 + 7;
string s;
int nxt[maxn], num[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("data.txt","w",stdout);
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int T;
cin >> T;
while (T--)
{
cin >> s;
nxt[0] = -1, nxt[1] = 0;
num[0] = 0, num[1] = 1;
ull ans = 1;
for (int i = 1, j = 0; i < s.length(); i++)
{
while (j != -1 && s[i] != s[j])
j = nxt[j];
nxt[i + 1] = ++j;
num[i + 1] = num[j] + 1;
}
for (int i = 1, j = 0; i < s.length(); i++)
{
while (j != -1 && s[i] != s[j])
j = nxt[j];
j++;
while (j * 2 > i + 1)
j = nxt[j];
ans = ans * (num[j] + 1) % mod;
}
cout << ans << '\n';
}
//fclose(stdin);
//fclose(stdout);
return 0;
}