HDU6357 Hills And Valleys

本来看了题解尝试自己写,然后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;
}

猜你喜欢

转载自blog.csdn.net/liufengwei1/article/details/81484153
今日推荐