uoj#529. 【美團杯2020】114514

題目描述


題解

必須要發掘出性質才能搞,亂找找不滿

一草稿紙的114514越看越草

發現5只出現一次,而且14是114的子串

顯然可以想到每次按最近的來匹配,一次找出一個114514

發現114511451414會掛掉,原因是把第二個5的114給拆掉了

1的數量最多,所以只考慮總量不考慮單獨每個

對比一下4的兩種用法,14必須要在5的後面並且少一個1,114沒有限制並且多一個1

那麼14即有限制又更優,所以肯定是能匹配14就匹配

然後就回到了上面的錯誤做法

考慮哪裏會掛掉,每個5前面必須要留一個4,所以只需要保證匹配完14後每個5都能匹配一個4即可

把4當成+1,5當成-1,前綴和就是可以匹配14(選1145不改變前綴和)的數量,用隊列即可求得限制,當一個5被選的時候判斷是否要彈掉隊頭

找數用並查集,時間複雜度O(nα)

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
//#define file
using namespace std;

const int b[6]={0,0,1,2,0,1};
int fa[3][600002],ans[100001][6],D[600002][2],Q,n,m,i,j,k,l,s1,s2,s3,h,t,H,T,s;
char st[600001];

int gf(int T,int t)
{
	static int d[600002],tot,i;
	tot=0;
	while (fa[T][t]!=t) d[++tot]=t,t=fa[T][t];
	fo(i,1,tot) fa[T][d[i]]=t;
	
	return t;
}

int main()
{
	#ifdef file
	freopen("uoj529.in","r",stdin);
//	freopen("uoj529.out","w",stdout);
	#endif
	
	scanf("%d",&Q);
	for (;Q;--Q)
	{
		scanf("%s",st+1);n=strlen(st+1);m=n/6;
		h=1;t=0;
		
		fa[0][0]=fa[1][0]=fa[2][0]=1;
		fa[0][n+1]=fa[1][n+1]=fa[2][n+1]=n+1;
		s1=s2=s3=n+1;
		fd(i,n,1)
		{
			switch (st[i])
			{
				case '1':{s1=i;break;}
				case '4':{s2=i;break;}
				case '5':{s3=i;break;}
			}
			fa[0][i]=s1,fa[1][i]=s2,fa[2][i]=s3;
		}
		
		l=0;H=1;T=0;
		fo(i,1,n)
		if (st[i]=='4') ++l;
		else
		if (st[i]=='5')
		{
			--l;
			while (T && D[T][1]>=l) --T;
			++T;D[T][0]=i;D[T][1]=l;
		}
		
		s=0;D[++T][1]=n;D[T][0]=0;
		while (h<=m)
		{
			if (h<=t && s<D[H][1])
			{
				j=ans[h][3];
				fo(k,4,5) j=gf(b[k],j),ans[h][k]=j,fa[b[k]][j]=j+1,++j;
				++h,++s;
			}
			else
			{
				++t,j=0;
				fo(k,0,3) j=gf(b[k],j),ans[t][k]=j,fa[b[k]][j]=j+1,++j;
				if (D[H][0]==ans[t][3]) ++H;
			}
		}
		fo(i,1,m) {fo(j,0,5) printf("%d ",ans[i][j]);printf("\n");}
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章