1 条题解
-
0
思路
反向Trie连接最近单词后缀,先学祖先形成树;相邻子树交换使贡献差为两子树大小之差,故按子树大小递增遍历,不能仅按单词长度或字典序贪心;n十万、总长51万,答案可超过32位。
参考程序(C++11)
#include <bits/stdc++.h> using namespace std; struct Node{int ch[26];int word;Node(){memset(ch,0,sizeof(ch));word=0;}}; int main(){ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;vector<Node>tr(1);vector<vector<int>>child(n+1);for(int id=1;id<=n;id++){string s;cin>>s;int v=0;for(auto it=s.rbegin();it!=s.rend();++it){int c=*it-'a';if(!tr[v].ch[c]){int u=tr.size();tr[v].ch[c]=u;tr.emplace_back();}v=tr[v].ch[c];}tr[v].word=id;} vector<pair<int,int>>q(1,{0,0});while(!q.empty()){auto p=q.back();q.pop_back();int v=p.first,ancestor=p.second;if(tr[v].word){int u=tr[v].word;child[ancestor].push_back(u);ancestor=u;}for(int c=0;c<26;c++)if(tr[v].ch[c])q.push_back({tr[v].ch[c],ancestor});} vector<int>order(1,0),sz(n+1,1);for(int i=0;i<(int)order.size();i++)for(int v:child[order[i]])order.push_back(v);for(int i=n;i>0;i--)for(int v:child[order[i]])sz[order[i]]+=sz[v];for(auto &a:child)sort(a.begin(),a.end(),[&](int u,int v){return sz[u]<sz[v];});vector<int>st(1,0),pos(n+1);int timer=0;long long ans=0;while(!st.empty()){int u=st.back();st.pop_back();if(u)pos[u]=++timer;int next=pos[u]+1;for(int v:child[u]){ans+=next-pos[u];next+=sz[v];}for(auto it=child[u].rbegin();it!=child[u].rend();++it)st.push_back(*it);}cout<<ans<<'\n';}
- 1