ABC225F String Cards

题意

给你 n 个串 si,你需要选出 k 个串并按照某个顺序拼接起来形成的字符串字典序最小。

n,k,|s|50

分析

由于顺序不固定,所以我们无法直接 DP。而状压的复杂度也太高了,怎么办呢?

考虑钦定一个顺序,使得按照这个顺序排列字符串一定最优。

一个经典的错误想法是:将字符串按照字典序升序排序。

hack:ba b,最优排列是 bab,但由于 b<ba,所以我们的程序会得出 bba 的结果。

考虑 exchange argument 贪心,设字符串 s,t 交换后一定不优,那么我们有 s+tt+s。事实上,以 s+t<t+s 排序是正确的。为什么呢?

考虑把这两个字符串写成哈希的形式,即 F(s)=i=0lenplenisiF(t) 同理。我们写出 F(s+t),F(t+s),首先注意到这两个串长度相等,那么 s+t<t+s 当且仅当 F(s+t)<F(t+s),而 F(s+t)=p|t|F(s)+F(t),F(t+s)=p|s|F(t)+F(s),所以有 p|t|F(s)+F(t)<p|s|F(t)+F(s),移项得 F(s)p|s|1<F(t)p|t|1,发现等式两边只跟 s,t 有关,而且由于这是数值,所以天然具有传递性、自反性。于是这样排序就是对的了。

关于 DP,我们仍然有一个经典错误想法:设 fi,j 表示前 i 个串中选了 j 个串的最小字典序,转移 fi,j=min(fi1,j,fi1,j1+si)。hack 考虑 bab 两个串,它们之后都要接 qwqwq 这个串,不难发现 baqwqwq 是字典序最小的,但由于 b 字典序比 ba 小,所以 DP 出来的方案是 bqwqwq,本质上是因为当字符串长度不相同时,我们只考虑一开始的字典序大小关系,而没有考虑拼上字符串后的字典序大小关系。也就是说,若要从前往后取,为了保证字典序比较正确,我们还需要记录一维状态表示取的字符串长度,这样复杂度五方,就又上天了。

这种正着 DP 要记录很多额外状态的题,有一种经典方案是考虑倒着 DP。设 fi,j 表示 in 这些串选 j 个拼成的最小字典序。这样我们就把字符串长度的状态扔掉了(由于是向前拼接所以对字典序大小关系必然不影响),转移方程类似,复杂度四方。

代码非常好写:

const int maxn=55;
int n,k;
string s[maxn],f[maxn][maxn];
bool cmp(string x,string y){return x+y<y+x;}
void solve_the_problem(){
	cin>>n>>k;
	rep(i,1,n)cin>>s[i];
	sort(s+1,s+n+1,cmp);
	rep(i,1,n)f[i][1]=s[i];
	per(i,n-1,1)rep(j,2,n)rep(k,i+1,n)if(f[k][j-1]!=""){
		string res=s[i]+f[k][j-1];
		if(f[i][j]=="")f[i][j]=res;
		else f[i][j]=min(f[i][j],res);
	}
	string ans=f[1][k]; 
	rep(i,2,n)if(f[i][k]!="")ans=min(ans,f[i][k]);
	cout<<ans;
}

作者:dcytrl

出处:https://www.cnblogs.com/dcytrl/p/18442427

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   dcytrl  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示