【YBTOJ】【数位DP】擦除序列

擦除序列

给你一个由字母构成的字符串 (S) 。每一步都要擦除其中一个子序列,但要求被擦除的子序列必须是一个回文词。求擦除整个字符串的最少步数。
比如,将 ( exttt{abcba})( exttt{abyczbea}) 擦除,就是合理的一步。

(nleq16).

题解

没想到状压DP还可以这么用……

设状态表示每一位是否被擦去,对于每一个状态,枚举其子集并判断子集是不是回文串。

(但是因为智障错误调了快一个点……)

代码

#include <bits/stdc++.h>
#define fo(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
const int INF = 0x3f3f3f3f,N = 20,M = 1e5+5;
typedef long long ll;
typedef unsigned long long ull;
inline ll read(){
	ll ret=0;char ch=' ',c=getchar(); 
	while(!(c>='0'&&c<='9'))ch=c,c=getchar();
	while(c>='0'&&c<='9')ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
int n;
char a[N];
ll dp[M];
bool flg[M];
signed main(){
	memset(dp,0x3f,sizeof(dp));
	scanf("%s",a+1);
	n = strlen(a+1);
	dp[0] = 0;
	for(int i = 1 ; i < 1<<n ; i ++){
		char ch[N]; int cnt = 0;
		for(int j = 1 ; j <= n ; j ++)
			if(i & (1<<(j-1)))
				ch[++cnt] = a[j];
		flg[i] = 1;
		for(int j = 1 ; j <= (cnt+1)>>1 ; j ++)
			if(ch[j] != ch[cnt-j+1]) {flg[i] = 0;break;}
	}
	for(int i = 1 ; i < 1<<n ; i ++)	
		for(int j = i ; j ; j = (j-1) & i)
			if(flg[j])
				dp[i] = min(dp[i],dp[i^j] + 1);
	printf("%lld",dp[(1<<n)-1]);
}
原文地址:https://www.cnblogs.com/Shinomiya/p/15269720.html