HDU 4272 LianLianKan(状压DP)题解
题意:一个栈,每次可以选择和栈顶一样的数字,并且和栈顶距离小于6,然后同时消去他们,问能不能把所有的数消去
思路:一个数字最远能消去和他相距9的数,因为中间4个可以被他上面的消去。因为还要判断栈顶有没有被消去,所以10位dp。dp[i][j]表示第i个栈顶状态为j能否存在,用1表示某位被消去。那么直接状压DP,假如被消去了则dp[i + 1][j >> 1] = 1。
输入看成了自顶向下,疯狂wa...
代码:
#include<set> #include<map> #include<cmath> #include<queue> #include<cstdio> #include<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 1000 + 10; const int M = maxn * 30; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1e4 + 7; int dp[maxn][1 << 10]; //栈顶为i,包括当前位的状态j,位1表示消去 int a[maxn]; int main(){ int n; while(~scanf("%d", &n)){ for(int i = n; i >= 1; i--) scanf("%d", &a[i]); if(n & 1) printf("0\n"); else{ int e; memset(dp, 0, sizeof(dp)); dp[1][0] = 1; for(int i = 1; i <= n; i++){ e = min(10, n - i + 1); for(int j = 0; j < (1 << e); j++){ if(dp[i][j] == 0) continue; if(j & 1){ //消去了 dp[i + 1][j >> 1] = 1; } else{ int num = 0; for(int k = 1; k < e; k++){ if(!((1 << k) & j)){ num++; if(num < 6 && a[i] == a[i + k]){ int st = j | (1 << k); dp[i + 1][st >> 1] = 1; } } } } } } printf("%d\n", dp[n][1]); } } return 0; }