【HDU 6578】[2019 HDU 多校第一场] Blank(dp)

题目

Problem Description

There are N blanks arranged in a row. The blanks are numbered 1,2,…,N from left to right.
Tom is filling each blank with one number in {0,1,2,3}. According to his thought, the following M conditions must all be satisfied. The ith condition is:
There are exactly xi different numbers among blanks ∈[li,ri].
In how many ways can the blanks be filled to satisfy all the conditions? Find the answer modulo 998244353.

Input

The first line of the input contains an integer T(1≤T≤15), denoting the number of test cases.
In each test case, there are two integers n(1≤n≤100) and m(0≤m≤100) in the first line, denoting the number of blanks and the number of conditions.
For the following m lines, each line contains three integers l,r and x, denoting a condition(1≤l≤r≤n, 1≤x≤4).

Output

For each testcase, output a single line containing an integer, denoting the number of ways to paint the blanks satisfying all the conditions modulo 998244353.

Sample Input

2
1 0
4 1
1 3 3

Sample Output

4
96

Source

2019 Multi-University Training Contest 1

题目传送门

思路

我们想到 d p [ i ] [ j ] [ k ] [ l ] dp[i][j][k][l] dp[i][j][k][l] 代表填完前 t t t 个位置后, { 0 , 1 , 2 , 3 } \left \{ 0, 1, 2, 3 \right \} {0,1,2,3} 4 4 4 个数字最后一次出现的位置,排序后按照第 t + 1 t+1 t+1 位,可以得到四种转移。
滚动掉一维,空间复杂度 O ( n 3 ) O(n^{3}) O(n3)
for循环4层,但是有顺序限制。时间复杂度差不多是 O ( n 4 ÷ 24 ) O(n^{4}\div 24 ) O(n4÷24)
很能接受

代码↓↓↓

代码

#include <bits/stdc++.h>

using namespace std;
const int M = 100 + 5;
int n, m, ans, dp[2][M][M][M];
vector <pair <int, int> > a[M];
const int mod = 998244353;

void sol(int &x) {
    if (x >= mod) x -= mod;
    (x >= mod) ? x -= mod : x;
}

int main() {
	int T, ans = 0, l, r, x;
	scanf("%d", &T);
    while (T--) {
        ans = 0;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) a[i].clear();
        for (int i = 0; i < m; i++)
            scanf("%d%d%d", &l, &r, &x), a[r].push_back(pair <int, int>(l, x));
        dp[0][0][0][0] = 1;
        for (int i = 1, p = 1; i <= n; i++, p ^= 1) {
        	for (int j = 0; j <= i; j++)
                for (int k = 0; k <= j; k++)
                    for (int l = 0; l <= k; l++)
            			dp[p][j][k][l] = 0;
            for (int j = 0; j < i; j++)
                for (int k = 0; k <= j; k++)
                    for (int l = 0; l <= k; l++) {
                        sol(dp[p][j][k][l] += dp[p^1][j][k][l]);
                        sol(dp[p][i-1][k][l] += dp[p^1][j][k][l]);
                        sol(dp[p][i-1][j][l] += dp[p^1][j][k][l]);
                        sol(dp[p][i-1][j][k] += dp[p^1][j][k][l]);
                    }
            for (int j = 0; j < i; j++)
                for (int k = 0; k <= j; k++)
                    for (int l = 0; l <= k; l++)
                        for (pair <int, int> t : a[i])
                            if (1 + (j >= t.first) + (k >= t.first) + (l >= t.first) != t.second)
                                dp[p][j][k][l] = 0;
        }
        for (int i = 0, p = n & 1; i < n; i++)
            for (int j = 0; j <= i; j++)
                for (int k = 0; k <= j; k++) sol(ans += dp[p][i][j][k]);
        printf("%d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值