CodeForces 1051d:连通块 DP

题面大意:有2*N的格子,每个格子可以涂成白色或者黑色,问有k个连通块的涂色方案数

N<=103,k<=2*103

我的错误思路:我没看懂题目对不起呜呜呜...

正解思路:

首先看到N<=103,反正凭我的感觉,一般来说103或者104这样的,很可能是DP或者记忆化,也就是N2的复杂度,100的话可能是dfs啊这样的爆搜,105可能就是nlogn或者n*o(1)了。

这是题外话,首先看一下,如果我要DP或者记忆化的话,那么首先要构建状态。复盘的话,我觉得那个N就是个暗示,也就是去以列为状态,结合最容易想到的从左向右推,那么第一个状态就是i列。光有列肯定不够,第二个状态就用题目中现成的状态:连通块。那么j代表连通块数目。然后尝试一下能不能推?我们发现,如果从左向右的话,当前最右边一列的组合是什么样是对新加进来组合后多出的连通块数目有影响(就是说,如果我要添加进来一个11,那么最后一列什么样对这个11加进来后,多出了多少个连通块是有影响的。)

那么也就有了第三个状态:最后一列的组合(正好只有4个,多了可能就开不下了)

有了状态,那么下面来看转移:

首先我要说一下我是选择了递推,如果是DP那样通过i-1这样的之前状态来确定当前状态,那么可能会访问越界...

转移其实就是一句话:枚举。

枚举什么?枚举最后一列长什么样,和新加进来那列长什么样,因为只有他们之间的关系对于新方案数有影响。

具体怎么枚举,详见代码~

#include <cstdio>
typedef long long int LL;
LL MOD=998244353,N,K,ans;
LL dp[1005][2005][5];//用1234分别表示00,01,10,11四种状态
int main(){
    scanf("%d%d",&N,&K);
    dp[1][1][1]=1;//dp[i][j][k]代表 i列,有j个连通块,最后一列状态为k的矩阵的填色方案数
    dp[1][2][2]=1;
    dp[1][2][3]=1;
    dp[1][1][4]=1;
    for(int i=1;i<=N;i++){
        for(int j=1;j<=2*N;j++){
            for(int k=1;k<=4;k++)dp[i][j][k]%=MOD;//别忘了%
            dp[i+1][j][1]+=dp[i][j][1];/*如果最后一列是1,新加进来一个1,那么连通块数目不会变*/
            dp[i+1][j+1][2]+=dp[i][j][1];/*如果最后一列是1,新家进来一个2,那么这是连通块数目多了一个,后面以此类推*/
            dp[i+1][j+1][3]+=dp[i][j][1];
            dp[i+1][j+1][4]+=dp[i][j][1];

            dp[i+1][j][1]+=dp[i][j][2];
            dp[i+1][j][2]+=dp[i][j][2];
            dp[i+1][j+2][3]+=dp[i][j][2];
            dp[i+1][j][4]+=dp[i][j][2];

            dp[i+1][j][1]+=dp[i][j][3];
            dp[i+1][j+2][2]+=dp[i][j][3];
            dp[i+1][j][3]+=dp[i][j][3];
            dp[i+1][j][4]+=dp[i][j][3];

            dp[i+1][j+1][1]+=dp[i][j][4];
            dp[i+1][j+1][2]+=dp[i][j][4];
            dp[i+1][j+1][3]+=dp[i][j][4];
            dp[i+1][j][4]+=dp[i][j][4];
        }
    }
    for(int i=1;i<=4;i++)
        ans+=dp[N][K][i];
    printf("%lld",ans%MOD);
    return 0;
}

原文地址:https://www.cnblogs.com/Zarax/p/12285566.html

时间: 2024-10-08 22:54:47

CodeForces 1051d:连通块 DP的相关文章

CodeForces - 1051D (线性DP)

题目:https://codeforces.com/problemset/problem/1051/D 题意:一个2行n列的矩形,上面有黑白块,然后问你怎么布置才能有k个连通块,问有多少种方案数 思路:其实就是一个矩阵,我们一次放一列 四种状态 黑    |   白 | 白 | 黑 白 |  黑 | 白 | 黑 我们dp[n][m][k],第n列第m种状态k个连通块的方案数,现在我们算放每个状态时,计算一次增加了多少个连通块 因为数组太大了,所以我们用滚动数组 然后递推就行了 #include<

Codeforces 278C Learning Languages(并查集) 求连通块

Codeforces 278C Learning Languages(并查集) 求连通块 为什么最后还要getfather 一遍 比如 x 是 y 的父亲 然后你 Union(x,z) 然后 z 变成了 x 父亲 然后 y 的祖先就是错的了 题解 求一个无向图中有几个连通块 sum 特判 一下 如果 每一个人的语言都为 0 则答案为 sum 其他 答案则为 sum - 1 1 #include <bits/stdc++.h> 2 using namespace std ; 3 4 const

Codeforces 920E Connected Components? 补图连通块个数

题目链接 题意 对给定的一张图,求其补图的联通块个数及大小. 思路 参考 ww140142. 维护一个链表,里面存放未归入到任何一个连通块中的点,即有必要从其开始进行拓展的点. 对于每个这样的点,从它开始进行 \(bfs\),将未被拓展到的点加入队列,并从链表中删除. 注意:写法上有一点要注意, 在处理完一整个连通块之后,记录下下一个连通块中的第一个点之后,再将最初的 \(src\) 从链表中删除.若一开始便删除,则会造成链表脱节. Code #include <bits/stdc++.h>

C. Edgy Trees Codeforces Round #548 (Div. 2) 并查集求连通块

C. Edgy Trees time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output You are given a tree (a connected undirected graph without cycles) of nn vertices. Each of the n−1n−1 edges of the tree is col

BZOJ 2730:[HNOI2012]矿场搭建(割点+连通块)

[HNOI2012]矿场搭建 Description 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口.请写一个程序,用来计算至少需要设置几个救援出口,以及不同最少救援出口的设置方案总数.Input 输入文件有若干组数据,每组数据的第一行是一个正整数 N(N≤500),表示工地的隧道数,接下来的 N 行每行是用空

UVALive-7303- Aquarium【最小生成树】【连通块】

UVALive - 7303- Aquarium 题目链接:7303 题目大意:给你一个r * c的格子,每个格子有一个 ' \ ' 或者 '/' 的墙,以及打掉墙的费用,问使得所有块联通的最小费用.(看图好理解) 题目思路:就是将他化成一个图,联通的块相当于一个点,两个点之间有一条边,边的权值为墙的费用. 转化为连通块的思路是:每个格子看成两部分,左侧和右侧.以一行来看,假设两个格子A,B.那么B格子的右侧的编号一定和A格子的左侧的编号相同.如图所示 给每个格子的左右侧标上号,然后加入边,边的

UVA 572 油田连通块-并查集解决

题意:8个方向如果能够连成一块就算是一个连通块,求一共有几个连通块. 分析:网上的题解一般都是dfs,但是今天发现并查集也可以解决,为了方便我自己理解大神的模板,便尝试解这道题目,没想到过了... 1 #include <cstdio> 2 #include <iostream> 3 #include <sstream> 4 #include <cmath> 5 #include <cstring> 6 #include <cstdlib&

洛谷P1141 //bfs求无向图的子连通块大小(多次询问)

http://www.luogu.org/problem/show?pid=1141 多询问题,求无向图的子连通块大小. 直接bfs,读一个搜一个,过60: 100%的点1,000,000个点,100,000次询问,显然是记忆化. 我很弱,最开始开了个数组记录每个点属于的连通块的第一个点的坐标,然后写了一堆,自己都烦. 后来问某大神,似拨开云雾见到了青天.用cnt记录连通块的" 名字 ". 学会了这一招,不代表过了. 我还是读一个点,如果访问过就输出,没访问就dfs,然后每dfs就循环

nyoj27-水池数目 (求连通块数目)【dfs】

http://acm.nyist.net/JudgeOnline/problem.php?pid=27 水池数目 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描述 南阳理工学院校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地图上仅标识了此处是否是水池,现在,你的任务来了,请用计算机算出该地图中共有几个水池. 输入 第一行输入一个整数N,表示共有N组测试数据每一组数据都是先输入该地图的行数m(0<m<100)与列数n(0