HDU - 6578 Blank DP + 滚动数组

HDU - 6578 Blank

题意

给你\(\{0,1,2, 3\}\)四个数,分别填入长度为\(n\)的数列中,有\(m\)个限制条件,\(l_{i}, r_{i}, x_{i}\)表示在\([l_{i}, r_{i}]\)区间内,只能有\(x_{i}\)个不同的数。问一共有多少总方案。

思路

首先, 我们可以用\(dp[i][j][k][w]\)来表示方案数,\(i, j, k, w\)不是特指对应某个数字,而是四种不同的数字从小到大最后出现的位置\((i < j < k <w)\)。
那么我们就能推出\(dp\)方程
\[ dp[i][j][k][w] += dp[i][j][k][w-1]\] \[dp[i][j][w-1][w] += dp[i][j][k][w-1]\] \[dp[i][k][w-1][w] += dp[i][j][k][w-1]\] \[dp[j][k][w-1][w] += dp[i][j][k][w-1]\]

我们发现后一位都只与\(w-1\)有关,\(100^{4}\)的空间太大,所以我们要做一个优化,把最后一维改成大小为\(2\)的滚动数组
那么我们现在的\(dp\)方程为
\[ dp[i][j][k][now] += dp[i][j][k][pre]\] \[dp[i][j][pre][now] += dp[i][j][k][pre]\] \[dp[i][k][pre][now] += dp[i][j][k][pre]\] \[dp[j][k][pre][now] += dp[i][j][k][pre]\] \[now = (pre+ 1)\%2 = pre \oplus1\]
转移\(dp\)的时候考虑一下限制条件就\(OK\)啦

AC代码

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <cfloat>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e2 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 998244353;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;
ll dp[maxn][maxn][maxn][3];
vector< pair<int,int> > lim[maxn];
int check(int a, int b, int c, int d){  //a < b < c < d
    for(int i = 0; i < lim[d].size(); i++){
        int x = lim[d][i].se;
        int l = lim[d][i].fi;
        if(x == 1 && l <= c)
            return 0;
        if(x == 2 && (l <= b || l > c))
            return 0;
        if(x == 3 && (l <= a || l > b))
            return 0;
        if(x == 4 && (l > a))
            return 0;
    }
    return 1;
}

int main() {
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        int l, r, x;
        for(int i = 1; i <= n; i++){
            lim[i].clear();
        }
        for(int i = 1; i <= m; i++){
            scanf("%d%d%d", &l, &r, &x);
            lim[r].push_back(make_pair(l, x));
        }

        dp[0][0][0][0] = 1;
        int  now = 1;
        ll ans = 0;
        for(int w = 1; w <= n; w++){
            for(int k = 0;  k <= w;k++){    //每次初始化,据说memset会T,要手动初始化
                for(int j = 0; j <= k; j++){
                    for(int i = 0; i <= j; i++){
                       dp[i][j][k][now] = 0;
                    }
                }
            }
            for(int k = 0; k < w; k++){
                for(int j = 0; (!k && j <= k) || j < k; j++){           //(!k&&j <=k):比自己后一位为0的时候,本身也能等于0,反之小于后一位
                    for(int i = 0; (!j && i <= j) || i < j; i++){
                        if(!check(i, j, k, w-1)){      //不符合限制条件的,令dp = 0
                            dp[i][j][k][now^1] = 0;
                            continue;
                        }
                        dp[i][j][k][now] = (dp[i][j][k][now] + dp[i][j][k][now^1])%mod;
                        dp[i][j][w-1][now] = (dp[i][j][w-1][now] + dp[i][j][k][now^1])%mod;
                        dp[i][k][w-1][now] = (dp[i][k][w-1][now] + dp[i][j][k][now^1])%mod;
                        dp[j][k][w-1][now] = (dp[j][k][w-1][now] + dp[i][j][k][now^1])%mod;
                    }
                }
            }
            now ^= 1;
        }
        now ^= 1;   //这边不要漏了
        for(int k = 0;  k < n;k++){
            for(int j = 0; (!k && j <= k) || j < k; j++){
                for(int i = 0; (!j && i <= j) || i < j; i++){
                    if(check(i, j, k, n))   //这边要判断一下是否符合限制条件
                        ans = (ans + dp[i][j][k][now])%mod;
                }
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/zhuyou/p/11273721.html

时间: 2024-10-17 13:12:52

HDU - 6578 Blank DP + 滚动数组的相关文章

HDU 3392 Pie(DP+滚动数组)

题意:有一些男生女生,男生女生数量差不超过100 ,男生女生两两配对.要求求出一种配对方法,使每一对的高度差的和最小. 思路:(我是真的笨笨笨!!磨磨唧唧写一堆是因为我笨!我看了别人的博客,思路全是学别人的,轻喷!)设人少的一组人数为n,b[],人多的一组人数为m,g[](b[],g[]先排好序),用dp[i][j]表示n中的前i个人与m中的前j个人配对所得到的最小值. 那么dp[i][j]就是min(dp[i-1][k]+|b[i]-g[k]|),就是n中前i-1个人和m中前1~k个人配对的最

HDU 1024 Max Sum Plus Plus --- dp+滚动数组

HDU 1024 题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交. 解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值,其中第i个子序列包括a[j], 则max(dp[m][k]),m<=k<=n 即为所求的结果 <2>初始状态: dp[i][0] = 0, dp[0][j] = 0; <3>状态转移: 决策:a[j]自己成为一个子段,还是接在前面一个子段的后面 方程: a[j]直接接在前面

HDU 5617 Jam&#39;s maze dp+滚动数组

题目链接: hdu: http://acm.hdu.edu.cn/showproblem.php?pid=5617 bc(中文):http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=666&pid=1003 题解: 设dp[x1][x2][i]表示第i步时,从(1,1)点走到了(x1,y1),(n,n)点走到了(x2,y2)点的合法的总数. 1 #include<iostream> 2 #include

[ACM] HDU 4576 Robot (概率DP,滚动数组)

Robot Problem Description Michael has a telecontrol robot. One day he put the robot on a loop with n cells. The cells are numbered from 1 to n clockwise. At first the robot is in cell 1. Then Michael uses a remote control to send m commands to the ro

HDU - 2294 Pendant (DP滚动数组降维+矩阵快速幂)

Description On Saint Valentine's Day, Alex imagined to present a special pendant to his girl friend made by K kind of pearls. The pendant is actually a string of pearls, and its length is defined as the number of pearls in it. As is known to all, Ale

HDU 5119 Happy Matt Friends (背包DP + 滚动数组)

题目链接:HDU 5119 Problem Description Matt has N friends. They are playing a game together. Each of Matt's friends has a magic number. In the game, Matt selects some (could be zero) of his friends. If the xor (exclusive-or) sum of the selected friends'ma

poj3624 01背包入门 dp+滚动数组

poj3624 01背包 dp+滚动数组 Charm Bracelet Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 25458   Accepted: 11455 Description Bessie has gone to the mall's jewelry store and spies a charm bracelet. Of course, she'd like to fill it with the bes

POJ3071-Football(概率DP+滚动数组)

Football Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2769   Accepted: 1413 Description Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In each round of the tournament, all teams still in the

HDU - 1024 Max Sum Plus Plus(dp+滚动数组优化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 题意:给定n个数字,求其中m段的最大值(段与段之间不用连续,但是一段中要连续) 例如:2 5 1 -2 2 3 -1五个数字中选2个,选择1和2 3这两段. 题解:dp[i][j]从前j个数字中选择i段,然后根据第j个数字是否独立成一段,可以写出 状态转移方程:dp[i][j]=max(dp[i][j-1]+num[j],max(dp[i-1][k])+num[j]) 这里的max(dp[i-