本来看了题解尝试自己写,然后WA倒怀疑人生,完全不知道怎么记录翻转的区间
于是对着https://blog.csdn.net/qq_34454069/article/details/81475646改代码,改到几乎一样了才过= =,我发现每次我的dp记录方案都会WA到怀疑人生,菜不成声.jpg。
我们设b数组为翻转后的区间0,1,2,.xy,(y-1)..x,y,y+1,9,spl为翻转的左区间端点,spr为翻转的右区间端点,记住翻转区间端点部分x,y出现了2次,然后对a数组和b数组进行最长公共子序列的操作。神奇的地方来了,对于f[i][j]表示a数组前i位于b数字前j位匹配的最优值,设tl[i][j]为到f[i][j]取最优值的时候左区间端点的翻转最左位置在哪里,tr[i][j]为右区间端点翻转的最右位置,然后在j=spl 和 j=spr的时候猜对tl[i][j]和tr[i][j]进行值的更新,不然直接等于以前的值。
注意一个问题,a[i]位置等于b[j]的时候才能选,而且选的时候要么从f[i-1][j]转移过来,要么从f[i-1][j-1]转移过来,也就是a[i]作为b[j]的第一个,我并不知道上面贴的链接里的代码为什么这一句不加也A了。
第二种情况,如果f[i][j-1]>f[i][j]的话,转移过来,说明此时值选b[1]到b[j-1]得到最优值,因为状态是f[i][j]表示a数组前i位于b数字前j位匹配的最优值,有可能中间有个值不匹配不存在,依然继续维护处最优值进行后面的dp。
#include<cstdio>
#include<cstring>
#define maxl 100010
int n,len,spl,spr,ansl,ansr,ans;
int a[maxl];
int b[22],num[22];
int f[maxl][22];
int tl[maxl][22],tr[maxl][22];
char s[maxl];
bool in[11];
inline void prework()
{
scanf("%d",&n);
scanf("%s",s+1);
memset(in,false,sizeof(in));
for(int i=1;i<=n;i++)
a[i]=s[i]-'0',in[a[i]]=true;
len=0;
for(int i=0;i<=9;i++)
if(in[i])
num[++len]=i;
}
inline int dp(int cnt)
{
for(int j=0;j<=cnt;j++)
f[0][j]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=cnt;j++)
{
f[i][j]=f[i-1][j];
tl[i][j]=tl[i-1][j];
tr[i][j]=tr[i-1][j];
if(b[j]==a[i])
{
f[i][j]=f[i-1][j]+1;
if(f[i-1][j-1]+1>f[i][j])
{
f[i][j]=f[i-1][j-1]+1;
tl[i][j]=tl[i-1][j-1];
tr[i][j]=tr[i-1][j-1];
}
if(spl==j&&tl[i][j]==0)
tl[i][j]=i;
if(spr==j)
tr[i][j]=i;
}
if(f[i][j-1]>f[i][j])
{
f[i][j]=f[i][j-1];
tl[i][j]=tl[i][j-1];
tr[i][j]=tr[i][j-1];
}
}
int tmp=0;tmp=f[n][cnt];
/*for(int j=1;j<=len;j++)
if(f[n][j]>tmp)
tmp=f[n][j];*/
return tmp;
}
inline void mainwork()
{
for(int l=1;l<=len;l++)
b[l]=num[l];
ans=dp(len);ansl=1;ansr=1;
int tmp;
for(int i=1;i<=len;i++)
for(int j=i+1;j<=len;j++)
{
int cnt=0;
for(int l=1;l<=i;l++)
b[++cnt]=num[l];
spl=cnt+1;
for(int l=j;l>=i;l--)
b[++cnt]=num[l];
spr=cnt;
for(int l=j;l<=len;l++)
b[++cnt]=num[l];
tmp=dp(cnt);
if(tmp>ans && tl[n][cnt] && tr[n][cnt])
{
ans=tmp;
ansl=tl[n][cnt];ansr=tr[n][cnt];
}
}
}
inline void print()
{
printf("%d %d %d\n",ans,ansl,ansr);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}