Blank(dp)

Blank

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

题意:就是有n长度的空位待你去填数,填的数的范围为0,1,2,3四种,但是有m个限制条件,每一限制条件代表L到R区间内恰有X个不同的数,问一共有多少种填数方案

题解:看了比赛题解才会做这道题,dp[i][j][k][l]表示前i个数中0,1,2,3最后一次出现的位置排序(降序)后为i,j,k,l的填数方案数

转换方程为分为四种情况:

1. 第i位出现的数和第i-1位出现的数一样,dp[i][j][k][l] += dp[i-1][j][k][l]

2.第i位出现的数和第j位出现的数一样,dp[i][i-1][k][l] += dp[i-1][j][k][l]

3.第i位出现的数和第k位出现的数一样,dp[i][i-1][j][l] += dp[i-1][j][k][l]

4.第i位出现的数和第l位出现的数一样,dp[i][i-1][j][k] += dp[i-1][j][k][l]

然后再计算dp的过程中,我们再加上限制条件,就能得到答案,具体看下面代码(C++会t,G++不会t)

看了标程,标程滚动了一维,优化了一下空间,但是不优化空间也过了,可能是数据的原因,下面就贴没有优化空间的代码,方便理解

//#include<bits/stdc++.h>
//#include<unordered_map>
//#include<unordered_set>
#include<iostream>
#include<sstream>
#include<iterator>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<vector>
#include<bitset>
#include<climits>
#include<queue>
#include<iomanip>
#include<cmath>
#include<stack>
#include<map>
#include<ctime>
#include<new>

using namespace std;
#define LL long long
#define ULL unsigned long long
#define MT(a, b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f;
const int O = 1e6;
const int mod = 998244353;
const int maxn = 1e2 + 5;
const double PI = acos(-1.0);
const double E = 2.718281828459;
const double eps = 1e-8;

int dp[maxn][maxn][maxn][maxn];

vector< pair <int, int > >v[maxn];

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

int main(){
    int T; scanf("%d", &T);
    while( T --) {
        int n, m; scanf("%d%d", &n, &m);
        for(int i=0; i<=n; i++) v[i].clear();
        for(int i=0; i<m; i++) {
            int L, R, X; scanf("%d%d%d", &L, &R, &X);
            v[R].push_back( pair <int, int >(L, X) );
        }

        dp[0][0][0][0] = 1;

        for(int i=1; i<=n; i ++) {

            for(int j=0; j<=i; j++)
                for(int k=0; k<=j; k++)
                    for(int l=0; l<=k; l++) dp[i][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++){
                        MOD(dp[i][j][k][l] += dp[i-1][j][k][l]);
                        MOD(dp[i][i-1][k][l] += dp[i-1][j][k][l]);
                        MOD(dp[i][i-1][j][l] += dp[i-1][j][k][l]);
                        MOD(dp[i][i-1][j][k] += dp[i-1][j][k][l]);
                    }

            if(v[i].size() == 0) continue;
            for(int j=0; j<=i; j++)
                for(int k=0; k<=j; k++)
                    for(int l=0; l<=k; l++)
                        for(int t=0; t<v[i].size(); t++) {
                            int L = v[i][t].first;
                            int X = v[i][t].second;
                            int cnt = 1 + (j >= L) + (k >= L) + (l >= L);
                            if(cnt != X) dp[i][j][k][l] = 0;
                        }

        }

        int ans = 0;
        for(int j=0, i=n; j<=n; j++)
            for(int k=0; k<=j; k++)
                for(int l=0; l<=k; l++)
                    MOD(ans += dp[i][j][k][l]);
        printf("%d\n", ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值