题意

给定一个长 $n$ 的序列 $a_i$ ,可以进行操作,每次操作选区间 $[l,r]$ ,条件是 $\wedge_{i=l}^{r}~a_i=0$ ,操作完会删除 $[l,r]$ 。问最多操作次数。

$n,a_i\lt64$

题解

区间 DP。设 $f_{l,r}$ 表示若区间 $[l,r]$ 可以合法,它的最大值,考虑 $l<k_1\leq k_2<r$ ,是 $f_{k_1,k_2}$ 搞完后搞 $f_{l,r}$ 。做完再扫一遍。

$\mathcal{O}(n^4)$

代码

挂了。

const int N = 70;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n;
	int a[N];
	int f[N][N], g[N];
	int main () {
		n = Read();
		for (int i = 1; i <= n; i++) a[i] = Read();
		for (int l = 1; l <= n; l++) {
			int val = a[l];
			for (int r = l; r <= n; r++) {
				val &= a[r];
				if (!val) f[l][r] = 1;
			}
		}
		for (int len = 3; len <= n; len++) {
			for (int l = 1; l + len - 1 <= n; l++) {
				int r = l + len - 1;
				int val1 = a[l];
				for (int k1 = l + 1; k1 <= r; val1 &= a[k1], k1++) {
					int val2 = a[r];
					for (int k2 = r - 1; k2 >= k1; val2 &= a[k2], k2--) {
						if (!f[k1][k2] || (val1 & val2)) continue;
						if (!val1 && !val2) f[l][r] = max(f[l][r], f[k1][k2] + 2);
						else f[l][r] = max(f[l][r], f[k1][k2] + 1);
					}
				}
			}
		}
//		for (int len = 1; len <= n; len++)
//			for (int l = 1; l <= n; l++)
//				printf("%d\t%d\t%d\n", l, len + l - 1, f[l][l + len - 1]);
		for (int i = 1; i <= n; i++) {
			for (int l = i; l; l--) {
				for (int r = l; r <= i; r++) {
					for (int j = l - 1; j >= 0; j--) {
						g[i] = max(g[i], g[j] + f[l][r]);
					}
				}
			}
		}
		printf ("%d\n", g[n]);
		return 0;
	}
}

int main () {
//	freopen("ex_eat4.in", "r", stdin);
//	freopen(".out", "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2023-11-11 15:01:40
博客类型