标签:freopen oid 关系 分类 否则 type sum define har
一个长度2n的ab各n个的ab串,每次可以同时删第i个a和第i个b,求剩下的最大字典序的串
n<=3000
菜
把a当作+1b当作-1,在前缀和为0的位置划开变成若干段,那么删只会影响到段的内部
结论:在同一个段内,每个ab对(x,y)的x和y的大小关系相同,否则一定会经过前缀和为0的位置
把以a开头的称为A段,b开头的称为B段,分类讨论
对于一个A段,如果后面有B段就全删掉最优
那么有效的A段是最大全A后缀,并且剩下的一定是abababab...的形式最优,因此贪心选即可
对于一个B段,设第一个选的组i为(x,y),那么y+1~x-1中的b一定全选最优,于是又会往后选一些a,如此选下去最后一定会把>=i的组全选掉(因为只有结尾处前缀和为0,如果在中间停了就矛盾了)
所以只有len/2+1种选法,暴力枚举判断即可
之后从后往前贪心选择合并,时间复杂度O(n^2)
#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 min(a,b) (a<b?a:b)
#define ll long long
//#define file
using namespace std;
struct type{
char a[6001];
int n;
void add(char ch) {a[++n]=ch;}
} ans,s,Ans;
int a[6001][3],c[6001][2],n,i,j,k,l,sum,tot,s1,s2;
char st[6001];
bool bz;
bool pd(type a,type b)
{
int i;
fo(i,1,min(a.n,b.n))
if (a.a[a.n-i+1]!=b.a[b.n-i+1])
return a.a[a.n-i+1]<b.a[b.n-i+1];
return a.n<b.n;
}
int main()
{
#ifdef file
freopen("agc026e.in","r",stdin);
#endif
scanf("%d",&n);
scanf("%s",st+1);
fo(i,1,n+n)
{
if (!sum)
{
++tot;
a[tot][0]=i;
a[tot][2]=st[i]==‘b‘;
}
sum+=(st[i]==‘a‘)?1:-1;
if (!sum) a[tot][1]=i;
}
fd(l,tot,1)
if (!a[l][2])
{
if (!bz)
{
s1=s2=0;
fo(i,a[l][0],a[l][1])
{
if (st[i]==‘a‘)
++s1,c[s1][0]=i;
else
++s2,c[s2][1]=i;
}
k=(a[l][1]-a[l][0]+1)/2,j=0;
fo(i,1,k)
if (j<c[i][0])
ans.add(‘b‘),ans.add(‘a‘),j=c[i][1];
}
}
else
{
bz=1;Ans=ans;
fd(i,(a[l][1]-a[l][0]+1)/2,0)
{
s=ans;
s1=s2=0;
fd(j,a[l][1],a[l][0])
{
if (st[j]==‘a‘)
{++s1;if (s1<=i) s.add(‘a‘);}
else
{++s2;if (s2<=i) s.add(‘b‘);}
}
if (pd(Ans,s)) Ans=s;
}
ans=Ans;
}
fd(i,ans.n,1) putchar(ans.a[i]);
putchar(‘\n‘);
fclose(stdin);
fclose(stdout);
return 0;
}
AGC026E - Synchronized Subsequence
标签:freopen oid 关系 分类 否则 type sum define har
原文地址:https://www.cnblogs.com/gmh77/p/13627997.html