1 条题解

  • 0
    @ 2026-5-5 11:05:57

    建出 Trie 树,发现题意就是在串后面加字符,让所有串都在不同叶子上。

    如果一个串落在深度为 depxdep_x 的点上,把它深度加到 depydep_y 的代价是 depydepxdep_y-dep_x。对于非叶节点 xx,我们要在它子树内加一个点,并把 xx 放过去。有两种情况:放到叶子下和非叶子节点的旁边。对于第一种,由于我们不能让串有祖先关系,需要把那个叶子也往下放一个,如果该叶子为 yy,代价就是 depydepx+2dep_y-dep_x+2,对于第二种情况,我们只需改变 xx 的深度,代价就是 depydepx+1dep_y-dep_x+1

    对于子树树根 xx,把 depx-dep_x 提出来,发现维护 depy+kdep_y+k 的最小值即可。这样从下往上贪是对的,因为一个点对于所有祖先的贡献一样,早用了不会劣。

    如何维护?启发式合并维护 set 就很好写。具体的,我们用小根堆维护子树内 depy+kdep_y+k 的最小值,把子树 set 合并起来,然后看 xx 是否为叶子节点,如果是,那就插入一个 depx+2dep_x+2,否则插入 depx+1dep_x+1。拿最小值更新答案,再删掉最小值。但我们发现一个问题:把 xx 移到 zz 后,上面的点还有可能再移到 zz 的子树里,于是就需要插入 depz+kdep_z+k,但我们无法通过 set 知道 zz 在树上的结构从而确定 kk,那么就要多记录一维信息。用 pair 存 depx+kdep_x+k 以及 flagflag,表示是否需要将 xx 的点也下移,这样就能维护了。

    具体实现可以看代码。

    #include<bits/stdc++.h>
    #define pi pair<int,int>
    #define fs first
    #define sc second
    #define for_(a,b,c) for(int a=b;a<=c;++a)
    using namespace std;
    int n;
    const int N=1e6+10;
    int dep[N],ch[N][2],num[N],tn=1;
    string cs;
    void add(){
    	cin>>cs;cs=' '+cs;
    	int x=1;dep[x]=1;
    	for_(i,1,cs.length()-1){
    		int op=cs[i]-'0';
    		if(!ch[x][op])ch[x][op]=++tn;
    		dep[ch[x][op]]=dep[x]+1;
    		x=ch[x][op];
    	}
    	num[x]++;
    }
    multiset<pi>s[N];
    int ans=0;
    void dfs(int x){
    	if(!x)return;
    	dfs(ch[x][0]);dfs(ch[x][1]);
    	if(!ch[x][0]&&!ch[x][1])s[x].insert({dep[x]+2,1}),--num[x];
    	else if(!ch[x][1])swap(s[x],s[ch[x][0]]),s[x].insert({dep[x]+1,0});
    	else if(!ch[x][0])swap(s[x],s[ch[x][1]]),s[x].insert({dep[x]+1,0});
    	else{
    		if(s[ch[x][0]].size()>s[ch[x][1]].size()){
    			swap(s[x],s[ch[x][0]]);
    			for(auto d:s[ch[x][1]])s[x].insert(d);
    		}
    		else{
    			swap(s[x],s[ch[x][1]]);
    			for(auto d:s[ch[x][0]])s[x].insert(d);
    		}
    	}
    	for_(i,1,num[x]){
    		auto it=s[x].begin();s[x].erase(it);
    		int d=it->fs;ans+=d-dep[x];
    		if(it->sc)s[x].insert({d+1,1}),s[x].insert({d+1,2});
    		else s[x].insert({d+2,1});
    	}
    }
    int main(){
    	ios::sync_with_stdio(0);cin.tie(0);
    	cin>>n;
    	for_(i,1,n)add();
    	dfs(1);
    	cout<<ans;
    	return 0;
    }
    
    • 1

    信息

    ID
    7598
    时间
    3000ms
    内存
    512MiB
    难度
    8
    标签
    递交数
    24
    已通过
    6
    上传者