codeforce 903F Clear the Matrix

来源:互联网 发布:叁度软件 编辑:程序博客网 时间:2024/05/13 23:33

这道题是一道DP题。

状态定义如下:d[i][j]表示从开始到第i-1列为止,全部已经变为dot,并且第i~i+3列状态为j时候的最小花费(由于第i~i+3一共16个位置,所以可以状态压缩,用一个int类型数j存储)。

想象我们对第i~i+3列进行操作的过程。假设这4列之前的状态为j,那么显然操作之后的新状态S<=j。所以每次操作都具有单调性。状态转移就比较明确了:

①当第i列全部是dot时,d[i][j]可以转变d[i+1][k],其中k是由j经过变化得到的i+1列~i+4列的状态。显然如果d[i][j]不能转变为d[i+1][j],那么我们需要对第i列添加子矩阵使得它将来能够转化为d[i+1][k],所以只要考虑对第i列操作的情况就可以了。
②为了降低每次由于子矩阵覆盖带来的额外复杂度,我们用一个mark[4]的vector来分别记录当子矩阵大小为p=i+1时候,将子矩阵放置在一个全为’*’的4x4矩阵的第一列后得到的状态。那么对于第二部分的状态转移,我们有:d[i][j&S]=min(d[i][j&S],d[i][j]+a[p])。
到这里,两种状态转移就完成了。下面贴上代码,124ms

#include<bits/stdc++.h>using namespace std;const int mx = 1e3 + 6;const int mm = (1 << 16) - 1;const int INF = 0x3f3f3f3f;int n, a[4], st[mx];//位压缩char s[4][mx];//读入字符串int d[mx][mm + 6];//d[i][j]表示0~i-1行都已经变成dot 并且i~i+3行的状态是jvector<int>mark[4];int main(){    scanf("%d", &n);    for (int i = 0; i < 4; i++)scanf("%d", &a[i]);    for (int i = 0; i < 4; i++)scanf("%s", s[i]);    for (int j = 0; j < n; j++) {        for (int i = 0; i < 4; i++) {            st[j] |= (s[i][j] == '*') << i;        }    }    memset(d, 0x3f, sizeof(d));    int S = 0;    for (int i = 0; i < 4; i++)S |= st[i] << (i * 4);    d[0][S] = 0;    for (int i = 1; i <= 4; i++) { //枚举方框的大小        for (int j = 0; j <= 4 - i; j++) {            mark[i - 1].push_back(mm);            int & SS = mark[i - 1].back();            for (int k = j; k < j + i; k++) {                for (int g = 0; g < i; g++) {                    SS ^= 1 << (g * 4 + k);   //预处理,使得每次覆盖操作可以在O(1)内完成                }            }        }    }    for (int i = 0; i < n; i++) {        for (int j = mm; j >= 0; j--) {            if (d[i][j] == INF)continue;//d[i][j]==INF表示该状态不可达            if (!(j & 15)) { //如果该状态可达,并且第i列全部都是dot                int SS = j >> 4 | (st[i + 4] << 12);//那么该状态可以转化成d[i+1][j&SS]                d[i + 1][SS] = min(d[i][j], d[i + 1][SS]);            }            for (int k = 1; k <= 4 && k + i <= n; k++) {                for (auto p : mark[k - 1]) {                    d[i][j&p] = min(d[i][j&p], d[i][j] + a[k - 1]);                }            }        }    }    printf("%d\n", d[n][0]);}