2019HDU多校第一场 HDU6578 Blank

http://acm.hdu.edu.cn/showproblem.php?pid=6578

题意:一排有N个空格。空格从左到右依次为1、2、…、N。

汤姆正在用{0,1,2,3}中的一个数字填充每个空格。根据他的想法,以下M个条件都必须满足。第i个条件为:

∈[li,ri]的空格中恰好有xi个不同的数。

做法:又是一道不会做的题,看了题解也不会,标程也看不懂,后来才发现,题解上dp[i][j][k][t]表示的是,这个是个数字最后出现的位置排序后是i,j,k,t,从小到大依次递增。而标程是依次递减。。。。我们就来标程的方法吧。这里只需要注意数字的位置就可以了。

dp[i][j][k][t]表示四个数字出现的最后位置分别是i,j,k,t而且从大到小。如果枚举第i位放的数字

第i位放的数字。如果和第i-1位放的相同则:dp[i][j][k][t]+=dp[i-1][j][k][t]

第i位放的数字。如果和第j位放的相同则:dp[i][i-1][k][t]+=dp[i-1][j][k][t]

第i位放的数字。如果和第j位放的相同则:dp[i][i-1][j][t]+=dp[i-1][j][k][t]

第i位放的数字。如果和第t位放的相同则:dp[i][i-1][j][k]+=dp[i-1][j][k][t]

显然可以滚动优化。

为什么会是这样的呢,因为在枚举的时候第i位肯定是最大的,肯定第一个是i而紧跟其后就是i-1而其他的位置不变,比如你要放在i位放第j的数字,则原理的位置就成了这样,i-1,i,k,t,重新排序就是如上,但不过这样一个条件就是j严格小于i

当然其他情况下,也可以要求k严格小于j,t严格小于k,但不过因为初始化dp[0][0][0][0],如果这样写会出现状态的无法(虽然后面无法转移是正确的)这样可能会不好写,因此只需要要求i和j就可以了。

关于检查,这个只需要判断在以i为右端点的区间中有满足条件的就可以了。这个看了代码都懂了。

#include "bits/stdc++.h"

using namespace std;
const double eps = 1e-8;
#define reg register
#define lowbit(x) x&-x
#define pll pair<ll,ll>
#define pii pair<int,int>
#define fi first
#define se second
#define makp make_pair

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return (x > 0) ? 1 : -1;
}

typedef long long ll;
typedef unsigned long long ull;
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const int N = 100000 + 10;
const int M = 1000 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
int dp[2][102][102][102];
int n, m;
vector<pii > v[102];

void add(int &x) {
    if (x >= mod) x -= mod;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        int l, r, x;
        for (int i = 1; i <= n; i++) {
            v[i].clear();
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &l, &r, &x);
            v[r].push_back(makp(l, x));
        }
        int p = 1;
        dp[0][0][0][0] = 1;
        for (int i = 1; i <= n; i++, p ^= 1) {
            for (int j = 0; j <= i; j++) {
                for (int k = 0; k <= j; k++) {
                    for (int t = 0; t <= k; t++) {
                        dp[p][j][k][t] = 0;
                    }
                }
            }
            for (int j = 0; j < i; j++) {
                for (int k = 0; k <= j; k++) {
                    for (int t = 0; t <= k; t++) {
                        add(dp[p][j][k][t] += dp[p ^ 1][j][k][t]);
                        add(dp[p][i - 1][k][t] += dp[p ^ 1][j][k][t]);
                        add(dp[p][i - 1][j][t] += dp[p ^ 1][j][k][t]);
                        add(dp[p][i - 1][j][k] += dp[p ^ 1][j][k][t]);
                    }
                }
            }
            for (int j = 0; j < i; j++) {
                for (int k = 0; k <= j; k++) {
                    for (int t = 0; t <= k; t++) {
                        for (auto g:v[i]) {
                            if (1 + (j >= g.fi) + (k >= g.fi) + (t >= g.fi) == g.se) continue;
                            dp[p][j][k][t] = 0;
                        }
                    }
                }
            }
        }
        p ^= 1;
        int ans = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= i; j++) {
                for (int k = 0; k <= j; k++) {
                    ///if (i == j || j == k) printf("%d %d %d %d\n", i, j, k, dp[p][i][j][k]);
                    add(ans += dp[p][i][j][k]);
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/97103495
今日推荐