【YBTOJ】【數位DP】擦除序列
阿新 • • 發佈:2021-09-15
擦除序列
給你一個由字母構成的字串 \(S\) 。每一步都要擦除其中一個子序列,但要求被擦除的子序列必須是一個迴文詞。求擦除整個字串的最少步數。
比如,將 \(\texttt{abcba}\) 從 \(\texttt{abyczbea}\) 擦除,就是合理的一步。\(n\leq16\).
題解
沒想到狀壓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]); }