uoj#529. 美团杯2020114514
Posted gmh77
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uoj#529. 美团杯2020114514相关的知识,希望对你有一定的参考价值。
题目描述
题解
必须要发掘出性质才能搞,乱找找不满
一草稿纸的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("
");}
}
fclose(stdin);
fclose(stdout);
return 0;
}
以上是关于uoj#529. 美团杯2020114514的主要内容,如果未能解决你的问题,请参考以下文章