2020暑期训练7

字符串

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值