ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Vještica

2022-07-26 18:02:22  阅读:149  来源: 互联网

标签:字符 const 每个 int 合并 wh tica Vje


link

给定一些串,每个串可以进行重组,最小化这些串最后组成的Trie的结点数。

数据范围指向状压DP。很明显最后的答案和每个串一开始的字符顺序无关,于是可以记录每个串中每个字符的数量。然后发现在两个串合并的时候,为了使得树上结点最少,考虑贪心地把相同的字符排到前面去,于是最后的答案是 \(len_1+len_2-same\)。然后考虑推广,两个集合合并的时候由于两边都会把相同的部分作为每个串的前缀,所以这些串的共同部分是可以作为前缀的,更新即可。

会发现线性更新是错误的,比如下面的数据:

4
dabcrs
eabcrs
ex
ey

先合并后面三个串会使得 e 放在第一层,这样只能节省两个字符;而先合并前面两个串则可以节省后面的五个字符,所以需要枚举子集,用两个子集的答案去更新大的集合。复杂度为 \(O(3^NN)\)。

code

#include<bits/stdc++.h>
//#define feyn
const int N=30;
const int M=1000010;
const int S=1<<16;
using namespace std;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}

char w[M];
int m,num[N][N];
int f[S],s[N];

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	memset(f,0x3f,sizeof(f));
	read(m);
	for(int i=1;i<=m;i++){
		scanf("%s",w+1);
		int len=strlen(w+1);
		f[(1<<i-1)]=len;
		for(int j=1;j<=len;j++)num[i][w[j]-'a']++;
	}
	for(int i=1;i<(1<<m);i++){
		if(f[i]<M)continue;
		memset(s,0x3f,sizeof(s));
		for(int j=1;j<=m;j++){
			if((i&(1<<j-1))==0)continue;
			for(int k=0;k<26;k++)s[k]=min(s[k],num[j][k]);
		}
		for(int j=i;j;j=(j-1)&i)f[i]=min(f[i],f[j]+f[i-j]);
		for(int j=0;j<26;j++)f[i]-=s[j];
	}
	printf("%d\n",f[(1<<m)-1]+1);
	
	return 0;
}

标签:字符,const,每个,int,合并,wh,tica,Vje
来源: https://www.cnblogs.com/dai-se-can-tian/p/16521977.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有