The 2022 ICPC Asia Hangzhou Regional Programming Contest--M题 (字典树)

发布时间 2023-05-04 16:31:04作者: N再再

https://codeforces.com/gym/104090/problem/K

题意:给你n个字符串,在给你m个字符大小顺序规则。求逆序对数量。

1. 常规求这n个字符串的逆序对数量O(n^2)的时间复杂度,必爆,肯定要想办法优化,就往预处理上想。

2. 在不同规则下,比较这n个字符串谁大,两个字符串比较谁大,无论什么字符串大,都是比较顺序遍历到双方不同字符时,在按规则比。就可以转化为比较两个不同字符的出现的前后顺序。且在比较时要保持前面字符相同。

// Problem: K. Master of Both
// Contest: Codeforces - The 2022 ICPC Asia Hangzhou Regional Programming Contest
// URL: https://codeforces.com/gym/104090/problem/K
// Memory Limit: 1024 MB
// Time Limit: 1000 ms

#include <bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;

// #define x first
// #define y second
#define NO cout << "NO" << '\n';
#define YES cout << "YES" << '\n';
#define int long long

const int N = 2e6 + 10;
int son[N][30], cnt[N][30], idx, sum[100][100];
char s[N];
int pos[N];

void insert()
{
	int p = 0; // p代表前i个字符相同的情况。
	for (int i = 0; s[i]; i ++)
	{
		int u = s[i] - 'a' + 1;
		if (!son[p][u]) son[p][u] = ++ idx;
		for (int j = 0; j < 27; j ++)
		{
			sum[j + 1][u + 1] += cnt[p][j]; // 记录j字符在前,i字符在后的的数量。
		}
		cnt[p][u] ++;  // 记录每个字符的出现情况且是前i-1个字符相同的情况下。
		p = son[p][u];
	}
}

void solve()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++) 
    {
    	cin >> s;
    	int len = strlen(s);
    	s[len] = 'z' + 1; // 可能会出现abc 和 abcd 的情况, 这样为了避免无字符可比, 就直接定义一个不可能出现的数,并把这个数标记成字符大小最小。
    	s[len + 1] = 0;
    	insert();
    }
    
    // for (int i = 0; i < 27; i ++)
	// {
		// for (int j = 0; j < 27; j ++)
		// {
			// cout << sum[i + 1][j + 1] << ' ';
		// }
		// cout << '\n';
	// }
    
    while (m --)
    {
    	cin >> (s + 1);
    	s[0] = 'z' + 1;
    	for (int i = 0; i < 27; i ++)
    	{
    		pos[s[i] - 'a' + 1] = i;
    	}
    	int ans = 0;
    	for (int i = 0; i < 27; i ++)
    	{
    		for (int j = 0; j < 27; j ++)
    		{
    			if (pos[i] > pos[j])
    			{
    				ans += sum[i + 1][j + 1];
    			}
    		}
    	}
    	cout << ans << '\n';
    }
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cout<<fixed<<setprecision(15);
	// freopen("input.txt", "r", stdin);
	// freopen("input.txt", "w", stdout);
    //init();
    int _ = 1;
    //cin >> _;
    while (_ --) solve();
    return 0;
}