首页 > 其他分享 >[ARC058F] 文字列大好きいろはちゃん

[ARC058F] 文字列大好きいろはちゃん

时间:2024-10-07 21:00:46浏览次数:4  
标签:文字 return int 大好 mid ARC058F mod include define

题意

给定 \(n\) 个字符串 \(s_i\),你需要选择若干个字符串按从前往后的顺序拼起来使得总长为 \(k\) 且字典序最小,保证有解。

\(n\le 2000,k\le 10^4,\sum |s_i|\le 10^6\)

分析

先考虑一个显然的暴力 DP:设 \(f_{i,j}\) 表示前 \(i\) 个串总长为 \(j\) 的最小字典序(注意这里由于限制了长度所以无需倒序转移),复杂度 \(O(nk^2)\),无法通过。

考虑优化,发现很多状态实际上是不会成为最优状态的。

首先做一个简单的小剪枝:预处理 \(g_{i,j}\) 表示用 \([i,n]\) 中的串能否拼出长为 \(k\) 的字符串,计算的复杂度是 \(O(\frac{nk^2}{w})\),那么我们在转移 \(f_{i,j}\) 时如果 \(g_{i+1,k-j}=0\) 那么状态 \(f_{i,j}\) 不合法,必然不会成为最优状态。

因为我们需要的是字典序最小,而如果一个方案在转移前就存在某一位比另一个方案大,那么前一种方案就是没用的。不难发现,对于一个 \(i\),所有可能成为最优状态的 \(f_{i,*}\) 互为前缀关系。把长度最大的那个 \(f_{i,*}\) 取出来,设为 \(t_i\),那么所有的 \(f_{i,*}\) 都是 \(t_i\) 的一段前缀。那么在 \(i\) 之下的所有合法状态均可以用一个数 \(j\) 表示。

考虑转移。把 \(f_{i-1,*}\) 的合法状态压成一个单调栈,从顶到底长度递降排序。令 \(b_j=f_{i-1,j}+s_i\),显然 \(b_i\) 的数量等于栈大小。考虑把一个 \(b_i\) 压进栈,若 \(b_i\) 的字典序比栈顶的字典序要大,那么这个 \(b_i\) 就废了;若比栈顶小,那么弹出栈顶,直到栈顶是 \(b_i\) 的前缀或者栈为空(注意不会发生比栈顶字典序大的情况,否则会在初始被废掉)。

现在我们就把时间复杂度降为了 \(O(nkT(|S|))\),其中 \(T(|S|)\) 是处理字符串比较的时间复杂度。发现我们在比较字符串字典序大小时比较的是 \(f_{i,*}+b_*\) 之间的大小关系,后面的 \(b_*\) 可以为空。设要比较的是 \(s_1=f_{i,x}+b_i\) 和 \(s_2=f_{i,y}+b_i\),设 \(x<y\),由于 \(f_{i,*}\) 是 \(t_i\) 的一段前缀,所以在 \([1,x]\) 这段前缀上两串相等,问题转化为 \(b_i\) 和 \(t_i[x+1,y]\) 比较大小,若两者相等再比较 \(b_i[y-x,\cdots]\) 和 \(b_i\) 的大小。发现这就是 Z 函数模板题(求字符串与本身每个后缀和另一个串的每个后缀的 LCP)。使用 Z 函数做到 \(T(|S|)=O(1)\) 或者偷懒用字符串哈希做到 \(T(|S|)=O(\log |S|)\),可以通过。

代码使用字符串哈希。里面有巨量注释及调试痕迹,谨慎阅读。

点击查看代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0)
#define OTIE cout.tie(0)
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define all(x) x.begin(),x.end()
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) (x&-x)
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mem(x,y) memset(x,y,sizeof x)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
typedef long long i64;
typedef unsigned long long u64;
using pii=pair<int,int>;
bool greating(int x,int y){return x>y;}
bool greatingll(long long x,long long y){return x>y;}
inline int rd(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}return x*f;
}
inline void write(int x,char ch='\0'){
	if(x<0){x=-x;putchar('-');}
	int y=0;char z[40];
	while(x||!y){z[y++]=x%10+48;x/=10;}
	while(y--)putchar(z[y]);if(ch!='\0')putchar(ch);
}
bool Mbg;
const int maxn=2e3+5,maxm=1e4+5,inf=0x3f3f3f3f;
const bool zgc_ak_ioi=true;
const int mod=787838027,base=59;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,k;
string s[maxn];
bitset<maxm>g[maxn];
string t[maxn];
//tv[i]:f[i-1][j]是否有值 
bool tv[maxm];
//(前缀长度,是否接上i)
pii sta[maxm];
int tp;
//f[i][j]的表示 
pii b[maxm];

int h[2][maxm];
int mi[maxm];
int hi[maxm];
int z[maxm];
//hi[i] LCP(str,str[i~end])
//z[i] LCP(str,txt[i~end])
inline int get(int l,int r){
	return (h[1][r]-(l?(1ll*h[1][l-1]*mi[r-l+1]%mod):0)+mod)%mod;
}
inline int __get__(int l,int r){
	return (h[0][r]-(l?(1ll*h[0][l-1]*mi[r-l+1]%mod):0)+mod)%mod;
}
void init(string str,string txt){
	int len1=str.size(),len2=txt.size();
	h[0][0]=str[0]-'a';
	rep(i,1,len1-1)h[0][i]=(1ll*h[0][i-1]*base%mod+str[i]-'a')%mod;
	h[1][0]=txt[0]-'a';
	rep(i,1,len2-1)h[1][i]=(1ll*h[1][i-1]*base%mod+txt[i]-'a')%mod;
	
	rep(i,0,len1-1){
		int l=0,r=len1-1-i,res=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(h[0][mid]==__get__(i,i+mid))res=mid+1,l=mid+1;
			else r=mid-1;
		}
		hi[i]=res;
	}
	rep(i,0,len2-1){
		int l=0,r=min(len1-1,len2-1-i),res=0;
		while(l<=r){
			int mid=(l+r)>>1;
			if(h[0][mid]==get(i,i+mid))res=mid+1,l=mid+1;
			else r=mid-1;
		}
		z[i]=res;
	}
}
//_ 下标
//0 y是x前缀 -1 y<x 1 y>x 
/*
case 1:
--------++++++
-----++++++
case 2:
-----------
----+++++
*/
int cmp(pii x,pii y,int _){
	int rev=1;
	if(x.fi<y.fi)swap(x,y),rev=-1;
	if(!y.se)return 0;
	int len=s[_].size();
	int __len__=y.fi+len;
	if(__len__<=x.fi){//case 2 
		if(z[y.fi]>=len)return 0;
		return s[_][z[y.fi]]<t[_-1][y.fi+z[y.fi]]?-rev:rev;
	}else{//case 1
		if(y.fi+z[y.fi]>=x.fi){
			if(!x.se)return 0;
			int num=x.fi-y.fi;
			if(num+hi[num]>=len)return 0;
			return s[_][num+hi[num]]<s[_][hi[num]]?-rev:rev;
		}else{
			return s[_][z[y.fi]]<t[_-1][y.fi+z[y.fi]]?-rev:rev;
		}
	}
}
inline void solve_the_problem(){
	cin>>n>>k;
	rep(i,1,n)cin>>s[i];
	mi[0]=1;rep(i,1,k)mi[i]=1ll*mi[i-1]*base%mod;
	g[n+1][0]=1;
	per(i,n,1)g[i]=g[i+1]|(g[i+1]<<s[i].size());
//	rep(i,1,n){
//		write(i,10);
//		rep(j,0,k)write(g[i][j],32);
//		P__;
//	}
	tv[0]=1;
	rep(_,1,n){
		init(s[_],t[_-1]);
		int len=s[_].size();
//		write(_,10);
//		rep(i,0,k)write(tv[i]);P__;
		rep(i,1,k)b[i]=mp(-1,-1);
		rep(i,1,k){
			if(tv[i])b[i]=mp(i,0);
			if(i>=len&&tv[i-len]){
				if(b[i]==mp(-1,-1)||(z[i-len]<len&&s[_][z[i-len]]<t[_-1][i-len+z[i-len]])){
					b[i]=mp(i-len,1);
				}
			}
		}
		tp=0;
		rep(i,1,k)if(b[i]!=mp(-1,-1)&&g[_+1][k-i]){
			while(zgc_ak_ioi){
				if(!tp){
					sta[++tp]=b[i];
					break;
				}
				int cp=cmp(b[i],sta[tp],_);
				if(!cp){
					sta[++tp]=b[i];
					break;
				}
				if(cp==-1)break;
				--tp;
			}
		}
//		write(_,10);
//		rep(i,1,tp)cerr<<t[_-1].substr(0,sta[i].fi)+(sta[i].se?s[_]:"")<<endl;
//		PU;
		t[_]=t[_-1].substr(0,sta[tp].fi)+(sta[tp].se?s[_]:"");
		tv[0]=1;rep(i,1,k)tv[i]=0;
		rep(i,1,tp)tv[sta[i].fi+sta[i].se*len]=1;
	}
//	rep(i,1,n)cerr<<t[i]<<endl;
	cout<<t[n];
}
bool Med;
signed main(){
//	freopen(".in","r",stdin);freopen(".out","w",stdout);
//	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	int _=1;IOS;
	while(_--)solve_the_problem();
}
/*
5 10
m
mmm
nnnnn
mm
mmnnnnnnn
*/

标签:文字,return,int,大好,mid,ARC058F,mod,include,define
From: https://www.cnblogs.com/dcytrl/p/18444186

相关文章

  • 如何修改网页文字或图片?
    修改网页上的文字或图片可以通过多种方式实现,具体取决于您的网站类型和技术栈。以下是详细的步骤和示例:1.使用CMS系统(如WordPress、Drupal等)修改文字登录后台:登录到CMS后台管理系统(例如WordPress的/wp-admin)。编辑页面或文章:导航到“页面”或“文章”部分,找到需要修......
  • 科研小tip2|OpenNI2环境配置(文字简要说明)
    在本栏科研小tip1中我分享了winpcap的可行安装方法,但并没有具体讲解环境配置方法,因为其他博主已经对winpcap的环境配置做了许多分享不过我个人在使用时遇到了按照步骤完成配置后,运行仍然出现提示OpenNI2.dll(OpenNI2动态库)不存在的报错,我想可能也有许多与我一样遇到这一问题的......
  • Vue2如何在网页实现文字的逐个显现
    目录Blue留言:效果图:实现思路:代码:1、空字符串与需渲染的字符串的定义2、vue的插值表达式3、函数4、mounted()函数调用结语:Blue留言:在国庆前夕,突发奇想,我想自己给自己做一个个人博客网站,但是我个人时间实在是太有限了,自己还有竞赛没完成,考研也在准备,怕不太好,就去......
  • Linux中 文字界面、X Window系统以及图形界面的关系
    Linux中文字界面、XWindow系统以及图形界面的关系在Linux系统中,文字界面(TTY)、XWindow系统(X11)以及图形界面(GUI)之间有明确的关系。下面分别解释它们的功能和相互之间的联系:1.文字界面(TTY)TTY(Teletypewriter)是Linux系统中的文本控制台。Linux系统默认提供了多个TTY,通常通过Ctr......
  • 在 PBootCMS 的首页上正确调用公司简介等频道的内容,并展示指定长度的文字内容
    假设你需要在首页调用公司简介频道的内容,并展示300个字符的内容,并添加“查看更多”的链接。HTML文件示例<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>首页-示例页面</title><basehref="http://www.exa......
  • vue2实现字体修改(全局/局部字体引入修改)/添加文字渐变色样式
    1.创建一个全局CSS文件创建一个单独的CSS文件,例如fonts.css,然后在main.js中引入。fonts.css文件内容:@font-face{font-family:'youshebiaotihei';src:url('../../fonts/youshebiaotihei.ttf')format('truetype');/*引用字体,但非全局使用*/font-wei......
  • C#名片识别接口集成方式、文字识别API
    名片识别接口通常是指通过OCR(光学字符识别)技术,对名片上的信息进行自动识别和提取的API服务。它能够快速、准确地将名片中的姓名、职位、公司、电话、邮箱、地址等信息转化为结构化的电子数据。基于深度学习算法的名片识别接口通常由第三方服务商来提供,如翔云等,标准化HTTP......
  • 中安未来 OCR—— 开启文字识别新时代
        在数字化的浪潮中,高效准确的文字识别技术正发挥着越来越重要的作用。今天,我要向大家介绍一款令人惊艳的OCR解决方案——中安未来OCR。一、初识中安未来OCR    中安未来OCR以其强大的功能和卓越的性能,在众多文字识别工具中脱颖而出。它能够快速......
  • 一种使用iText7渲染引擎去除文字水印方法的过程记录
    有一种PDF文本,使用旋转过的字体来作为水印。文件经过密码保护,不能通过编辑的方法去除。转载请保留这一段文字:charset#cnblogs,谢绝CSDN、知乎之流转载注意:拥有水印并且编辑密码包含的PDF文档可能具有版权保护,本文仅从技术角度讨论可能性。正常文件可以被打开而且显示无误,使用iTe......
  • MATLAB文字检测和识别系统
    MATLAB有很多功能强大的工具箱,可以用于图像处理和文字识别。可以使用MATLAB进行文字检测和识别系统的开发。文字检测是指识别图像中的文字区域。MATLAB提供了许多图像处理函数,可以用于文字检测。例如,可以使用边缘检测算法(如Canny边缘检测算法)来检测图像中的边缘。然后,可以使用......