BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈

奋斗吧
奋斗吧
擅长邻域:未填写

标签: BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈 Html/CSS博客 51CTO博客

2023-07-07 18:24:22 124浏览

BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈,这个题sasam都可做曾经作为一名sa选手BJ还是更倾向用sa于是先YY了sa做法但没写提供思路//觉得应该没什么bug搞完height单调栈来回


BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈_线段树

BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈_ios_02

BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈_#include_03

BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈_#include_04


这个题sa sam都可做

曾经作为一名sa选手 BJ还是更倾向用sa

于是先YY了sa 做法 但没写 提供思路 //觉得应该没什么bug

搞完height 单调栈来回扫两边

//想不明白就评个论 BJ涨涨评论/斜眼笑

扫出每个height对应lcp的区间 进行答案更新

第一问

我们都有height对应区间了 当然直接惩罚圆力就好了啊

第二问

不太清楚其他题解讲的并查集是什么鬼。。

还是利用已知的height对应区间

每个区间按height分割成了两半

在区间左半边 右半边 分别找出 maxa mina 之后两对数4种组合就可以更新答案了

//随便什么数据结构就好了啊 线段树啥的

/*

看其他题解写的只用 最大*最大 最小*最小 显然是错的啊。。。

大概是 因为是答案是后缀最大值 单调递增 不小心没卡掉吧。。。

随手卡啊。 {-1,-2} {1,2}

*/


之后后缀自动机做法就很套路了。。

串翻过来 parent tree 就是后缀树

直接树形dp就好了。。。

//代码短 又好YY 当然选择它

听说UOJ的hack数据很有趣1

于是在检查了程序鲁棒性后大力交了一发

本想写下在UOJ光荣AC 结果 这数据可真酸爽 /笑哭

//不过这鬼东西NOI 应该不会有吧。。。

BZOJ 4199: [Noi2015]品酒大会/UOJ #131. 【NOI2015】品酒大会 后缀自动机 树形dp / 后缀数组 单调栈_#include_05



#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;

typedef long long ll;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void print(ll x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=600100,inf=0X3f3f3f3f;
const ll Mn=-4485090715960753727;

int n;

struct SAM
{
	int trans[N][26],par[N],mx[N];
	int sz,root,suff;
	int size[N],V[N];
	bool book[N];
	int f[N][2];
	
	SAM(){sz=root=suff=1;}
	
	void insert(int x,int val)
	{
		int p=suff,np=++sz;
		size[np]=1;V[np]=val;book[np]=1;
		while(p && !trans[p][x])
			trans[p][x]=np,p=par[p];
		if(!p) par[np]=root;
		else
		{
			int q=trans[p][x];
			if(mx[q]==mx[p]+1) par[np]=q;
			else
			{
				int nq=++sz;
				mx[nq]=mx[p]+1;
				memcpy(trans[nq],trans[q],sizeof(trans[q]));
				par[nq]=par[q];
				par[q]=par[np]=nq;
				while(p && trans[p][x]==q)
					trans[p][x]=nq,p=par[p];
			}
		}
		suff=np;
	}
	
	void build(char *s,int *a)
	{
		register int i;
		for(i=1;i<=n;++i) insert(s[i]-'a',a[i]);
	}
	
	int last[N],ecnt;
	struct EDGE{int to,nt;}e[N];
	inline void add(int u,int v)
	{e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;}
	
	ll num[N],MX[N];
	
	void dp(int u)
	{
		if(book[u]) f[u][0]=f[u][1]=V[u];
		for(int i=last[u],v;i;i=e[i].nt)
		{
			v=e[i].to;
			dp(v);
			num[mx[u]]+=1ll*size[u]*size[v];
			size[u]+=size[v];
			
			if(f[v][0]!=inf)
			{
				if(f[u][0]!=inf)
					MX[mx[u]]=max(MX[mx[u]],1ll*f[u][0]*f[v][0]),
					MX[mx[u]]=max(MX[mx[u]],1ll*f[u][1]*f[v][1]),
					MX[mx[u]]=max(MX[mx[u]],1ll*f[u][0]*f[v][1]),
					MX[mx[u]]=max(MX[mx[u]],1ll*f[u][1]*f[v][0]),
					f[u][0]=max(f[u][0],f[v][0]),
					f[u][1]=min(f[u][1],f[v][1]);
				else f[u][0]=f[v][0],f[u][1]=f[v][1];
			}
		}
	}
	
	void solve()
	{
		register int i;
		for(i=2;i<=sz;++i)
			add(par[i],i);
		memset(f,0X3f,sizeof(f));
		memset(MX,-0X3f,sizeof(MX));
		dp(root);
		i=n;
		while(~(i--)) num[i]+=num[i+1];
		i=n;
		while(~i && MX[i+1]==Mn) MX[i+1]=0,i--;
		while(~i) MX[i]=max(MX[i],MX[i+1]),i--;
		
		for(i=0;i<n;++i)
			print(num[i]),putchar(' '),print(MX[i]),putchar('\n');
	}
}sam;

int a[N];
char s[N];

int main()
{
	n=read();
	scanf("%s",s+1);
	register int i;
	for(i=1;i<=n;++i) a[i]=read();
	if(n==1){puts("0 0");return 0;}
	reverse(s+1,s+1+n);
	reverse(a+1,a+1+n);
	sam.build(s,a);
	sam.solve();
	return 0;
}




好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695