CF GYM100739J.Longest cheap palindrome

LC.CF GYM100739J.Longest cheap palindrome

我们设\(f[i,j,k,l,r]\)表示:

当前左端取到了位置\(i\),右端取到了位置\(j\)

当前选择的子序列长度为\(k\)

区间\([i,l],[r,j]\)中所有字符都被选择时,最小要付出的代价。

转移很简单,枚举左右两边下一个字符选到哪里即可。

这里有一份\(O(n^8)\)的代码,按理说是过不去的,但是因为每一重循环内部都剪掉了很多枝,所以最终的结果是过掉了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,lim,res;
ll cost[34][34],f[2][34][34][34][34];//f[k,i,j,l,r]:leftmost at i, rightmost at j, length of 2k, [i,l] and [r,j] have been chosen
char s[50];
int main(){
	scanf("%d%d%d",&n,&m,&lim),memset(f,0x3f,sizeof(f));
	scanf("%s",s+1);
	for(int i=1,a,b,c;i<=m;i++)scanf("%d%d%d",&a,&b,&c),cost[a][b]+=c;
	for(int i=1;i<=n;i++)for(int j=i+2;j<=n;j++)if(s[i]==s[j])f[1][i][j][i][j]=cost[i][i]+cost[j][j];
	for(int k=1;(k<<1)<=n;k++){
		for(int i=1,j=i+(k<<1)-1;j<=n;i++,j++){
			bool ok=true;
			for(int l=0;l<k;l++)ok&=(s[i+l]==s[j-l]);
			if(!ok)continue;
			f[k&1][i][j][i+k-1][i+k]=0;
			for(int u=i;u<=j;u++)for(int v=u;v<=j;v++)f[k&1][i][j][i+k-1][i+k]+=cost[u][v];
		}
		memset(f[!(k&1)],0x3f,sizeof(f[!(k&1)]));
		for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)for(int l=i;l<=j;l++)for(int r=j;r>l;r--){
			if(f[k&1][i][j][l][r]>lim)continue;
			res=max(res,k<<1);
			for(int u=i-1;u;u--)for(int v=j+1;v<=n;v++){
				if(s[u]!=s[v])continue;
				if(l+1==r&&u==i-1&&v==j+1)continue;
				ll now=f[k&1][i][j][l][r];
				if(u==i-1)for(int w=u;w<=(l+1==r?j:l);w++)now+=cost[u][w];
				else now+=cost[u][u];
				if(v==j+1)for(int w=v;w>=(l+1==r?i:r);w--)now+=cost[w][v];
				else now+=cost[v][v];
				f[!(k&1)][u][v][u==i-1?l:u][v==j+1?r:v]=min(f[!(k&1)][u][v][u==i-1?l:u][v==j+1?r:v],now);
			}
		}	
	}
	printf("%d\n",res);
	return 0;
}

posted @ 2021-03-30 20:00  Troverld  阅读(30)  评论(0编辑  收藏  举报