[LOJ 6288]猫咪[CF 700E]Cool Slogans

摘要:
[LOJ6288]猫[CF700E]CoolSlogans主题是给出一个字符串(T),并找到一个最大值(K),从而有(S1,S2,dots,S_K)满足以下要求:(S1)是(T)的子字符串,(forall1lei˂K)具有(S_{i+1})是(S)的双子字符串。双子串的定义是:如果(a)在(b)的至少两个不同位置出现为子串,则(a)是(b)中的双子串。出现的位置可以重叠。(|T|le2imes10^5)。何时解决测试
[LOJ 6288]猫咪[CF 700E]Cool Slogans

题意

给定一个字符串 (T), 求一个最大的 (K) 使得存在 (S_1,S_2,dots,S_k) 满足 (S_1)(T) 的子串且 (forall 1le i< k)(S_{i+1})(S)双子串.

其中双子串的定义是: 若 (a)(b) 的至少两个不同位置作为子串出现则 (a)(b) 的双子串. 出现位置可以重叠.

(|T|le 2 imes 10^5).

题解

考试的时候被沙雕题目描述搞得迷迷糊糊的结果没发现是原题←菜的真实

显然对于每个子串我们可以这个子串里挑一个答案最大且的双子串作为这个子串的答案.

我们发现当我们挑出一个子串 (S_1) 后, 可以通过对左右端点进行适当缩减来刚好卡到"每一个双子串都是上一个串的一个border"的程度. 因为如果出现了不是border的情况, 可以把前面所有的 (S_i) 全都缩短, 不难发现这样并不会导致答案变劣.

那么实际上要计算的就是每个子串最多迭代几个border. 考虑在SAM上DP. SAM的结点上只能控制右端点, 左端点是一个区间, 不难发现只要搞右端点相同就可以了. 线段树合并搞出每个点的 right 集合, 判断一下答案最大的祖先是否能对当前点做出贡献就可以了. 能做出贡献就 (+1), 否则就不加.

至于判断, 因为当前 right 集合对应的长度最大为 len 的子串都是完全一样的, 所以随便取一个位置判断就可以了.

参考代码

#include <bits/stdc++.h>

const int MAXN=4e5+10;

struct Node{
	int l;
	int r;
	int cnt;
	Node* lch;
	Node* rch;
	Node(int,int);
	void Insert(int);
	int Query(int,int);
};
Node* N[MAXN];

int n;
int cnt=1;
int root=1;
int last=1;
int s[MAXN];
int prt[MAXN];
int len[MAXN];
int val[MAXN];
int pos[MAXN];
int tprt[MAXN];
char str[MAXN];
std::map<char,int> chd[MAXN];

int Extend(char);
Node* Merge(Node*,Node*);

int main(){
	scanf("%s",str+1);
	n=strlen(str+1);
	for(int i=1;i<=n;i++){
		int x=Extend(str[i]);
		N[x]->Insert(pos[x]=i);
	}
	for(int i=1;i<=cnt;i++)
		s[i]=i;
	std::stable_sort(s+1,s+cnt+1,[](int a,int b){return len[a]>len[b];});
	for(int i=1;i<cnt;i++){
		N[prt[s[i]]]=Merge(N[prt[s[i]]],N[s[i]]);
		pos[prt[s[i]]]=pos[s[i]];
	}
	int ans=0;
	for(int i=cnt-1;i>=1;i--){
		int p=s[i];
		if(prt[p]==root){
			val[p]=1;
			tprt[p]=p;
		}
		else{
			assert(N[p]->Query(pos[p],pos[p]));
			int last=tprt[prt[p]];
			int cnt=N[last]->Query(pos[p]-len[p]+(len[prt[last]]+1),pos[p]);
			if(cnt>=2){
				val[p]=val[last]+1;
				tprt[p]=p;
			}
			else{
				val[p]=val[last];
				tprt[p]=last;
			}
		}
		ans=std::max(ans,val[p]);
	}
	printf("%d
",ans);
	return 0;
}

void Node::Insert(int x){
	++this->cnt;
	if(this->l!=this->r){
		int mid=(this->l+this->r)>>1;
		if(x<=mid){
			if(this->lch==NULL)
				this->lch=new Node(this->l,mid);
			this->lch->Insert(x);
		}
		else{
			if(this->rch==NULL)
				this->rch=new Node(mid+1,this->r);
			this->rch->Insert(x);
		}
	}
}

int Extend(char x){
	int p=last;
	int np=++cnt;
	N[last=np]=new Node(1,n);
	len[np]=len[p]+1;
	while(p&&!chd[p].count(x))
		chd[p][x]=np,p=prt[p];
	if(!p)
		prt[np]=root;
	else{
		int q=chd[p][x];
		if(len[q]==len[p]+1)
			prt[np]=q;
		else{
			int nq=++cnt;
			N[nq]=new Node(1,n);
			len[nq]=len[p]+1;
			chd[nq]=chd[q];
			prt[nq]=prt[q];
			prt[q]=nq;
			prt[np]=nq;
			while(p&&chd[p][x]==q)
				chd[p][x]=nq,p=prt[p];
		}
	}
	return np;
}

Node* Merge(Node* a,Node* b){
	if(a==NULL)
		return b;
	if(b==NULL)
		return a;
	Node* cur=new Node(a->l,b->r);
	cur->cnt=a->cnt+b->cnt;
	cur->lch=Merge(a->lch,b->lch);
	cur->rch=Merge(a->rch,b->rch);
	return cur;
}

int Node::Query(int l,int r){
	if(l<=this->l&&this->r<=r)
		return this->cnt;
	else{
		int ans=0;
		if(this->lch&&l<=this->lch->r)
			ans+=this->lch->Query(l,r);
		if(this->rch&&this->rch->l<=r)
			ans+=this->rch->Query(l,r);
		return ans;
	}
}

Node::Node(int l,int r):l(l),r(r),cnt(0),lch(NULL),rch(NULL){}

[LOJ 6288]猫咪[CF 700E]Cool Slogans第1张

免责声明:文章转载自《[LOJ 6288]猫咪[CF 700E]Cool Slogans》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇大数据量下高并发同步的讲解数据库SQL优化大总结之 百万级数据库优化方案(转载)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

OpenWrt上搭建纯L2TP服务器[ZT]

转移自:http://www.openwrt.pro/post-389.html纯L2TP(L2TP+ppp,无IPSec)首先安装xl2tpd软件包opkgupdateopkginstallxl2tpd edit/etc/xl2tpd/xl2tpd。conf,并配置l2tp服务器[global]port=1701authfile=/etc/xl2tpd/x...

powerdesigner与数据库之间的连接

useUnicode=true&characterEncoding=UT8&serverTimezone=UTC 9JDBCdriverjarfiles:指定连接的jar包路径。测试连接。连接成功。进入工作区。3.2 3.2powerdesigner连接到oracle。其原理与连接MySQL的原理相同。在已安装的oracle下找到ojdbc1...

JAVA 实现CLOB转String

CLOB定义了用于在数据库中保存文件的类型。SQLCLOB是一种内置类型,它将一个大型字符对象作为列值存储在数据库表的一行中。默认情况下,驱动程序使用SQLlocator实现Clob对象,这意味着Clob对象包含指向SQLCLOB数据的逻辑指针,而不是数据本身。Clob对象在其创建的事务期间有效。在一些数据库系统中,文本也用作CLOB的别名。例如,SQL S...

IntelliJ idea设置显示错误代码提示

idea默认关闭自动编译,所以一些编译错误只有在编译的时候才会提示,例如修改了引用类。按图中设置打开自动编译:注意:idea默认打开省电模式,自动编译在省电模式下被禁用,所以需要在file˃powersavemode关闭省电模式。...

SQLServer2008/2012 安装、添加sa用户和密码、多实例安装、修改端口, 重启生效

因为我们无法使用sa用户登录,所以只能使用系统登录。登录后,我们需要修改相关属性。右键单击数据库,然后单击属性。在这个sa的登录属性对话框中,我们首先需要设置这个用户的密码。由于此用户名是系统的用户,我们可以直接填写密码,然后再次确认密码。然后在对话框中,单击左上角的第二个属性服务器角色。这是您要实现的添加用户的角色。...

建行手机银行4.0版本转账怎么不要求输入支付密码?

建行手机银行单笔限额50万,日限额100万,这个6位数的验证码价值50万元!输入6个数字的支付密码只需要几秒钟而已,转账操作频率不是很高,手机银行转账速度比人工柜台、ATM、电脑网银转账速度不知道快了多少倍,输入6个数字的支付密码这几秒钟相对安全性算什么呢?另外建行还有帐号支付的方式,对电子商户日限额10000元,只需要帐号+手机验证码就可以支付,密码都不用...