1. 程式人生 > 其它 >P3294 [SCOI2016]背單詞

P3294 [SCOI2016]背單詞

首先第一個是非常不划算的 所以我們想辦法先將沒有字首的前放進去

第二就是第三的特殊情況

有公共字尾的一定是連在一起的 幾堆不同公共字尾的 一定是先排數量小的一堆 因為這樣對後面幾堆產生的貢獻最小

最後說白了就是先按照sz排序 最後按照dfs序走一遍dfs統計答案就好

#include<cstdio>
#include<string>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
string a[100005];
int trie[510005][26],dp[510005],num[510005],numm;
bool yes[510005];
vector<int> edge[510005];
long long ans;
bool cmp(int x,int y){
    return dp[x]<dp[y];
}
void dfs(int x){
    int i;
    for(i=0;i<edge[x].size();i++){
        dfs(edge[x][i]);
        dp[x]+=dp[edge[x][i]];
    }
    sort(edge[x].begin(),edge[x].end(),cmp);
}
void dfs1(int x){
    int i;
    num[x]=numm++;
    for(i=0;i<edge[x].size();i++){
        ans+=numm-num[x];
        dfs1(edge[x][i]);
    }
}
bool cmp1(string x,string y){
    return x.size()<y.size();
}
int main(){
	int n,i,j,cnt=0;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		cin>>a[i];
	}
    sort(a+1,a+n+1,cmp1);
	for(i=1;i<=n;i++){
		int len,u=0,bj=0;
		for(j=a[i].size()-1;j>=0;j--){
			if(!trie[u][a[i][j]-'a']){
				trie[u][a[i][j]-'a']=++cnt;
			}
            if(yes[u]){
                bj=u;
            }
			u=trie[u][a[i][j]-'a'];
		}
        edge[bj].push_back(u);
        dp[u]=yes[u]=1;
	}
    dfs(0);
    dfs1(0);
	printf("%lld\n",ans);
	return 0;
}