首页 > 其他分享 >ABC225F String Cards

ABC225F String Cards

时间:2024-10-01 19:49:25浏览次数:8  
标签:String ABC225F 字符串 maxn Cards 字典 rep DP string

题意

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

\(n,k,|s|\le 50\)。

分析

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

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

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

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

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

考虑把这两个字符串写成哈希的形式,即 \(F(s)=\sum_{i=0}^{len} p^{len-i}s_i\),\(F(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)\),移项得 \(\dfrac{F(s)}{p^{|s|}-1}<\dfrac{F(t)}{p^{|t|}-1}\),发现等式两边只跟 \(s,t\) 有关,而且由于这是数值,所以天然具有传递性、自反性。于是这样排序就是对的了。

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

这种正着 DP 要记录很多额外状态的题,有一种经典方案是考虑倒着 DP。设 \(f_{i,j}\) 表示 \(i\sim n\) 这些串选 \(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;
}

标签:String,ABC225F,字符串,maxn,Cards,字典,rep,DP,string
From: https://www.cnblogs.com/dcytrl/p/18442427

相关文章

  • 【常用API】Object、Objects、包装类、StringBuilder、StringBuffer、StringJoiner
    API:应用程序编程接口就是java帮我们已经写好了一些程序,如:类、方法等,直接拿过来解决一些问题。1.Object它常用的方法:toString():返回对象的字符串形式;存在意义,让子类重写,以便返回子类对象的内容。equals():默认比较两个对象的地址是否相等;存在意义,让子类重写,以便用......
  • 【C++ STL】深入理解string类的底层实现
    string类的模拟实现一.string的构造与析构函数1.普通构造函数与析构函数2.拷贝构造的浅拷贝所带来的问题3.如何实现深拷贝二.运算符重载1.赋值运算符重载2.大小比较相关的运算符重载三.迭代器的实现四.string常用操作的实现1.静态const成员npos的定义2.插入操作3.查找......
  • WPF Progrss bar stringformat {} {0}% IsDetermined
    //xaml<Windowx:Class="WpfApp425.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.mi......
  • JS实现String.Format
    js实现string.format功能<scripttype="text/javascript">varerrorHtml="<atitle=\"{1}\"href=\"#\"onclick=\"\"class=\"ml-5\"style=\"text-decoration:none;color:#FF3C3......
  • C++ string的基本运用详细解剖
    string的基本操作一.与C语言中字符串的区别二.标准库中的string三.string中常用接口的介绍1.string中常用的构造函数2.string类对象的容量操作函数3.string类对象的访问及遍历操作4.string类对象的修改操作5.string类的非成员函数6.string中的其他一些操作一.与C语言......
  • 常用类--StringBuffer
    StringBuffer:可变的字符序列,可以看作一个存储字符的一个容器构造方法:publicStringBuffer()publicStringBuffer(intcapacity)publicStringBuffer(Stringstr)点击查看代码publicclassStringBufferDemo1{publicstaticvoidmai......
  • CF2019C Cards Partition
    涉及知识点:鸽巢原理,贪心前言唐诗题,赛时都已经想到了所有性质,以为要从数学方法上求解,却没想到就是个纯贪心题……题意Link给你一堆数,\(1,2,3,\dots,n\),分别有\(a[1],a[2],a[3],\dots,a[n]\)个,你还可以添加不超过\(k\)个数(当然这些数得是\(1\simn\)中的整数),你需要将它们......
  • 常用类--String
    ==比较:1、比较的是两个基本数据类型的话,比较两个数值是否相等2、比较的是两个引用数据类型的话,比较的是两个对象的地址值是否相等字符串:由若干个字符构成的字符序列叫做字符串String类代表字符串。字符串不变;它们的值在创建后不......
  • NSStringDrawingOptions
    在Swift中,boundingRect(with:options:attributes:context:)方法的options参数使用的是NSStringDrawingOptions枚举。以下是这个枚举的所有选项及其说明:NSStringDrawingOptions枚举usesLineFragmentOrigin说明:这个选项表示文本的计算是基于文本块的边界。即文本会......
  • C++中的string类
    前言C语言中字符串是以‘\0’结尾的字符的集合,为了方便操作,C标准库中提供了一些str系列的库函数,接下来我们学习string类。1.标准库中的string类1.1 string类在使用string类的时候,必须包含#include头文件以及usingnamespacestd;1.2auto和范围forauto关键词auto可以......