K. Master of Both
题目
Professor Hui-Bot is the master of string theory and advanced data structures, so he came up with an interesting problem. Given a sequence of nn strings consisting of only lowercase English letters, how many inversions are there in this sequence when the strings are compared by lexicographical order?
As the most extraordinary student of Hui-Bot, Putata and Budada mastered superb string theory and advanced data structure skills respectively, and they solved this problem together with ease. However, there are qq different parallel universes, where the characters in the alphabet are not appearing in the original order.
Formally, the alphabet in each universe is a string, which is a permutation of the 2626 lowercase English letter, denoting the order each character appears.
A string aa is lexicographically smaller than a string bb if and only if one of the following holds:
- aa is a prefix of bb, but a≠ba≠b;
- in the first position where aa and bb differ, the string aa has a letter that appears earlier in the alphabet than the corresponding letter in bb.
The number of inversions in a sequence aa of length nn is the number of ordered pairs (i,j)(i,j) such that 1≤i<j≤n1≤i<j≤n, aj<aiaj<ai.
Please help Putata and Budada in each universe to solve the problem.
题意
给n个由小写字母组成的串,给m个询问,每个询问为一个重新定义的字母表,问如果以这个字母表为基准,n个串有多少个逆序对
思路
如果每次去枚举每一个串显然是不现实的,考虑找两两串之间的比较关系,如果对于一个正常的字母表,比较两个字符串的字典序,首先肯定去找第一位不相同的位数。
而对于重新定义的字母表,必然也只是去判断第一位不同的字母的字典序先后关系,所以可以考虑把这些需要判断的字母关系先预处理存下来。
这样就想到字典树,在把每一个串放进字典树的同时,统计需要判断的不同字母之间的位数,最后在每次询问时可以做到快速累加。
需要注意的是,可能存在不论字母表如何变,一定存在的逆序对,如abcd和abc,所以我们在建字典树的同时也需要处理出那些不需要字母表就能判断出的逆序对。
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define double long double
typedef long long ll;
const int N = 1e6+100;
const int mod = 1e9+7;
const int INF = 0x3f3f3f3f3f3f;
int n,q;
int nxt[N][26];
int cnt[N];
int a[30][30];
int res=0;
int id=0;
void insert(string s) {
int l=s.size();
int p = 0;
for (int i = 0; i < l; i++) {
int x=s[i]-'a';
for(int j=0; j<26; j++) {
if(j==x)continue;
if(nxt[p][j]!=0) {
a[x][j]+=cnt[nxt[p][j]];
}
}
if (!nxt[p][x]) nxt[p][x] = ++id;
p = nxt[p][x];
cnt[p]++;
}
for(int i=0; i<26; i++) {
if(nxt[p][i]!=0)
res+=cnt[nxt[p][i]];
}
}
void solve() {
cin>>n>>q;
for(int i=1; i<=n; i++) {
string s;
cin>>s;
insert(s);
}
while(q--) {
string s;
cin>>s;
int ans=0;
for(int i=0; i<26; i++) {
int x=s[i]-'a';
for(int j=i+1; j<26; j++) {
int y=s[j]-'a';
ans+=a[x][y];
}
}
cout<<ans+res<<'\n';
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}