[BZOJ 3791] 作业 【DP】

题目链接:BZOJ - 3791

题目分析

一个性质:将一个序列染色 k 次,每次染连续的一段,最多将序列染成 2k-1 段不同的颜色。

那么就可以 DP 了,f[i][j][0|1] 表示到第 i 个位置,染了 j 段,当前这一段颜色为 0|1 的最大价值。

f[i][][] 只与 f[i-1][][] 有关,第一维用滚动数组就可以了。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>

using namespace std;

const int MaxN = 100000 + 5, MaxM = 100 + 5;

inline void Read(int &Num) {
	char c; c = getchar();
	while (c < ‘0‘ || c > ‘9‘) c = getchar();
	Num = c - ‘0‘; c = getchar();
	while (c >= ‘0‘ && c <= ‘9‘) {
		Num = Num * 10 + c - ‘0‘;
		c = getchar();
	}
}

inline int gmax(int a, int b) {return a > b ? a : b;}

int n, m, Ans;
int A[MaxN], f[3][MaxM][3];

int main()
{
	Read(n); Read(m);
	for (int i = 1; i <= n; ++i) Read(A[i]);
	int Now = 0, Last = 1;
	m = m * 2 - 1;
	Ans = 0;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			f[Now][j][0] = gmax(f[Last][j][0], f[Last][j - 1][1]);
			f[Now][j][1] = gmax(f[Last][j][1], f[Last][j - 1][0]);
			if (A[i] == 0) ++f[Now][j][0];
			else ++f[Now][j][1];
			Ans = gmax(Ans, f[Now][j][0]);
			Ans = gmax(Ans, f[Now][j][1]);
		}
		Now ^= 1; Last ^= 1;
	}
	printf("%d\n", Ans);
	return 0;
}

  

时间: 2024-12-13 11:04:12

[BZOJ 3791] 作业 【DP】的相关文章

bzoj 3791: 作业

23333开始了为期不知道多少天的DP专题23333 (上来第一个大水题就不会,跪) k次修改,最多会产生2*k-1个不同的区间..然后dp搞一下..(可以压一维) 1 /*#include<cstdio> 2 #include<iostream> 3 #define N 100005 4 using namespace std; 5 int n,K,size[N],a[N],f[55][N][2]; 6 int ans,pp,p,qq,q,tot; 7 int main() 8

bzoj 1597 斜率DP

1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5115  Solved: 1897[Submit][Status][Discuss] Description 农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地

bzoj 3668 数位DP

收获: 1.如果有很多位操作,并且不包含+-×/等高级运算,那么可以一位一位考虑,如果求一个最优解,可以尝试逐位确定,这道题因为原始攻击值有范围,那么就需要数位DP. 1 /************************************************************** 2 Problem: 3668 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:288 ms 7 Memory:804 kb 8 **

bzoj 1017 tree dp

这道题几经波折啊. 最开始和vfleaking一样,把题意理解错了,认为一个装备可能被多个装备依赖,然后想不出来,去看题解. 发现自己理解错了题意,自己想想,其实也不难想到dp[i][j][k]表示“i号节点代表的子树,用掉j的钱,给父亲预留k个自己(但还是父亲付钱)”的状态,写出来交上去就是T, 开始以为是常数问题,优化半天还是T,看了他人AC代码,才发现自己算法有一定问题:重复计算了很多东西. 树形动规,一般在大的树规下,每个节点还会对儿子们来一次”资源分配“,一般是用背包解决,这道题也是这

BZOJ 1996 合唱队(DP)

考虑从最后的队形开始依次还原最初的队形. 对于当前的队形,要么选最左边的,要么选最右边的. 如果选了左边的,那么下次选择的一定是大于它的.右边的同理. 所以定义dp[mark][l][r]为区间[l,r]的选择状态为mark的方法数. 然后记忆化搜索一下就可以了. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vect

BZOJ 1833 数位DP

思路: 数位DP f[i][j][k]表示走到第i位 开头位j 数字k 出现的次数 $f[i][j][k]+=f[i-1][l][k];$$f[i][j][j]+=base[i]$ calc的时候要有特殊的技巧...(我看题解学会的) //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long int

BZOJ 4321: queue2( dp )

dp(i, j, 1)表示前i个, 有j对是不合法的, i和i-1是在一起的. dp(i, j, 0)表示前i个, 有j对是不合法的, i和i-1不在一起的. 转移我们只需考虑是多了一对不合法的还是少了一对不合法的, 或者是不变, 考虑当前i和i-1,i-2的位置的影响就可以了. dp(i, j, 1) = 2*dp(i-1, j-1, 0) + dp(i-1, j-1, 1) + dp(i-1, j, 1) dp(i, j, 0) = (i-j-2)*dp(i-1, j, 0) + (j+1)

BZOJ 1068 (区间DP)

题意:字符串的压缩,f[l][r][0]代表还没M,f[l][r][1]代表有M. 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 int f[55][55][2],n; 7 char s[555]; 8 bool ok(int l,int r){ 9 int len=(r-l+1)/2; 1

bzoj 3851: 2048 dp优化

3851: 2048 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 22  Solved: 9[Submit][Status] Description Teacher Mai is addicted to game 2048. But finally he finds it's too hard to get 2048. So he wants to change the rule: You are given some numbers. Every