【bzoj4567】[Scoi2016]背单词 贪心+trie树

来源:互联网 发布:淘宝货源外国 编辑:程序博客网 时间:2024/04/30 11:28

我个傻逼,这么水的题还调了那么久。

把所有的串都反过来,建trie树,很明显,不同子树间是不影响的。
一定是先选择父亲节点再选子节点,同一个节点先选子树大小最小的儿子即可。

一开始想错了,以为可以直接再trie树上贪心,后来发现必须要建出新树,因为有的节点公用同一个祖先,但是祖先并不是单词节点,这就很尴尬了。


#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<iostream>#include<vector>#define maxn 100010#define N 520010using namespace std;int ch[N][26],size[N];vector<pair<int,int> > v[N];bool tag[N];int n,tot;long long ans,now;char s[N];void insert(){int len=strlen(s+1),x=0;for (int i=len;i>=1;i--){if (!ch[x][s[i]-'a']) ch[x][s[i]-'a']=++tot;x=ch[x][s[i]-'a'];}tag[x]=1;}void dfs(int x,int fa){if (tag[x]) v[fa].push_back(make_pair(x,0)),fa=x,size[x]=1;for (int i=0;i<26;i++)  if (ch[x][i]) dfs(ch[x][i],fa);for (int i=0;i<v[x].size();i++) size[x]+=size[v[x][i].first],v[x][i]=make_pair(size[v[x][i].first],v[x][i].first);sort(v[x].begin(),v[x].end());}void dfs1(int x,int w){now++;ans+=now-w;w=now;for (int i=0;i<v[x].size();i++) dfs1(v[x][i].second,w);}int main(){scanf("%d",&n);for (int i=1;i<=n;i++){scanf("%s",s+1);insert();}dfs(0,0);dfs1(0,0);printf("%lld\n",ans-1);return 0;}


0 0
原创粉丝点击