CodeForces 225C Barcode DP

也是一道dp ,想到了就会觉得很巧妙

矩阵中只有白块和黑块,要求repaint后满足下述条件:

  1. 每列一种颜色
  2. 根据输入范围x, y 要求条纹宽度在[x, y] 之间

数据范围: nmx and y (1 ≤ n, m, x, y ≤ 1000; x ≤ y).

求:满足条件最少repaint的次数

自己在YY的时候觉得这么大的数据范围肯定没得暴力,估计就dp 了= =

是可以想出这么个dp 公式: cur[][] = Sigma(x ~ y) Min( former[][] + Sum[] )

不过细节没有想全

看了Tutorial 后顿时明白了

题中只有两种颜色Black 和 White ,先作一个预处理使得可以求出任意posX 到 posY 之间White 和 Black 块的数目

然后就可以开始状态转移了~

最后的答案就是min(dp[0][m], dp[1][m]).

Source Code:

//#pragma comment(linker, "/STACK:16777216") //for c++ Compiler
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <stack>
#include <string>
#include <map>
#include <set>
#include <list>
#include <queue>
#include <vector>
#include <algorithm>
#define Max(a,b) (((a) > (b)) ? (a) : (b))
#define Min(a,b) (((a) < (b)) ? (a) : (b))
#define Abs(x) (((x) > 0) ? (x) : (-(x)))
#define MOD 1000000007
#define pi acos(-1.0)

using namespace std;

typedef long long           ll      ;
typedef unsigned long long  ull     ;
typedef unsigned int        uint    ;
typedef unsigned char       uchar   ;

template<class T> inline void checkmin(T &a,T b){if(a>b) a=b;}
template<class T> inline void checkmax(T &a,T b){if(a<b) a=b;}

const double eps = 1e-7      ;
const int N = 1              ;
const int M = 200000         ;
const ll P = 10000000097ll   ;
const int INF = 0x3f3f3f3f   ;

char a[1100][1100];
int v1[1100][2], v2[1100][2];
int dp[2][1100];

int main(){
    int i, j, k, t, n, m, numCase = 0;
    int x, y;
    while(cin >> n >> m >> x >> y){
        memset(v1, 0, sizeof(v1));
        for(i = 1; i <= n; ++i){
            for(j = 1; j <= m; ++j){
                cin >> a[i][j];
                if(‘#‘ == a[i][j])  ++v1[j][1];
                else    ++v1[j][0];
            }
        }
        v2[1][0] = v1[1][0];
        v2[1][1] = v1[1][1];
        for(i = 2; i <= m; ++i){
            v2[i][0] = v2[i - 1][0] + v1[i][0];
            v2[i][1] = v2[i - 1][1] + v1[i][1];
        }
        memset(dp, 0x3f, sizeof(dp));
        dp[0][0] = dp[1][0] = 0;
        for(j = 1; j <= m; ++j){
            for(int a = x; a <= y; ++a){
                if(j - a < 0)   break;
                checkmin(dp[0][j], dp[1][j - a] + v2[j][0] - v2[j - a][0]);
                checkmin(dp[1][j], dp[0][j - a] + v2[j][1] - v2[j - a][1]);
            }
        }
        cout << Min(dp[0][m], dp[1][m]) << endl;

    }

    return 0;
}
时间: 2024-11-05 19:30:55

CodeForces 225C Barcode DP的相关文章

codeforces 225C Barcode

题意:给你一个矩阵,只包含 '#' 和 '.',现在每一列必须相同,最多连续y列最少连续x列相同. 解题思路:3维dp,dp[i][j][k] 表示 第i列 ,状态j,是状态j的第K行. 解题代码: 1 // File Name: 225c.cpp 2 // Author: darkdream 3 // Created Time: 2015年03月09日 星期一 09时49分05秒 4 #include<climits> 5 #include<vector> 6 #include&

Codeforces 13C Sequence --DP+离散化

题意:给出一个 n (1 <= n <= 5000)个数的序列 .每个操作可以把 n 个数中的某一个加1 或 减 1.问使这个序列变成非递减的操作数最少是多少 解法:定义dp[i][j]为将前i个数变为以j为结尾的非递减序列的最少操作次数. 则有: dp[i][j] = min(dp[i][j], min(dp[i][k]) + Cost(原来第i个位置上的数转换到j))  (1 <= k <= j) 即前i个数以j结尾的状态可以由前i-1个数以小于等于j的k结尾的状态转移过来,取

Codeforces 77C 树形dp + 贪心

题目链接:点击打开链接 题意: 给定n个点, 每个点的豆子数量 下面是一棵树 再给出起点 每走到一个点,就会把那个点的豆子吃掉一颗. 问:回到起点最多能吃掉多少颗豆子 思路:树形dp 对于当前节点u,先把子节点v都走一次. 然后再往返于(u,v) 之间,直到u点没有豆子或者v点没有豆子. dp[u] 表示u点的最大值.a[u] 是u点剩下的豆子数. #include <cstdio> #include <vector> #include <algorithm> #inc

Codeforces 57C Array dp暴力找规律

题目链接:点击打开链接 先是计算非递增的方案, 若非递增的方案数为x, 则非递减的方案数也是x 答案就是 2*x - n 只需求得x即可. 可以先写个n3的dp,然后发现规律是 C(n-1, 2*n-1) 然后套个逆元即可. #include<iostream> #include<cstdio> #include<vector> #include<string.h> using namespace std; #define ll long long #def

Codeforces 413D 2048(dp)

题目连接:Codeforces 413D 2048 题目大意:2048的游戏,两个相同的数x可以变成一个2*x,先给出n,表示在一个1*n的矩阵上面玩2048,规定每次向左移动,并且每次出现一个,给出序列n,表示出现的块的值,0表示既可以是2也可以是4,问说有多少种可能,使得游戏结束后的最大块的值大于等于2^k. 解题思路:dp[i][j][x]表示第i个位置,值为j,x表示先前有没有出现过大于2^k的数: 这种递增的情况可以直接表示为14(总和,以为后面的2,4如果变大,就肯定能和8想合在一起

Codeforces 455A Boredom (dp)

很裸的dp 状态转移方程 dp[i]=max(dp[i-1],dp[i-2]+dp[i]*i) #include<bits/stdc++.h> using namespace std; long long dp[100020]; int main() { int n,a; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a); dp[a]++; } for(int i=2;i&

Codeforces 176B 经典DP

非常好的一个题目,CF上的DP都比较经典 题意就是 给定一个串A,B,正好执行K次操作,每次操作可以把 A串从中间切开,并调换两部分的位置,问最后得到B串共有多少种不同的切法(只要中间有一次不同,即视为不同) 首先,题目的一个关键点一定要抓到,就是 ,不管怎么切 然后调换位置,其实串根本没变,你把串想成一个环,从某一点分成两部分并且交换位置,其实就是把串的起点变到了该点,这是很关键也是最机智的一点 然后,我们要发现规律,你纸上模拟也行,推理也行.. 我们发现:1.首先原串(即以0号字母开头的)个

Nanami&#39;s Digital Board CodeForces - 434B (棋盘dp)

大意: 给定01矩阵, m个操作, 操作1翻转一个点, 操作2求边界包含给定点的最大全1子矩阵 暴力枚举矩形高度, 双指针统计答案 #include <iostream> #include <algorithm> #include <math.h> #include <cstdio> #include <set> #include <map> #include <string> #include <vector>

Codeforces Round #139 (Div. 2)C Barcode DP

#include<iostream> #include<cstdio> #include<cstring> using namespace std ; const int maxn = 1010; const int inf = 0x3f3f3f3f ; int dp[maxn][2] ; char str[maxn][maxn] ; int num[maxn]; int sum_b[maxn]; int sum_w[maxn]; int main() { // fre