首页 > 其他分享 >P10975 Mondriaan's Dream 解题报告

P10975 Mondriaan's Dream 解题报告

时间:2024-08-29 14:26:45浏览次数:10  
标签:cnt last int Mondriaan 伸出 state P10975 矩形 Dream

题目传送门

题目大意

给定一个 \(N\times M\) 的网格,求用 \(1\times 2\) 和 \(2\times 1\) 的长方形去铺满它有多少种方案。

数据范围:\(N,M\le 11\)。

思路:

考虑怎么放才能刚好填满网格。

可以想到,如果先放横着的,再放竖着的,那么当我们将横着的都放完后,若竖着的恰好能刚好嵌进去,说明这是一个合法方案。

也就是说,放完横着的矩形后放竖着的矩形的方法的唯一确定的,那么:

求总的方案数其实就是求横着放且合法(使竖着的能嵌进去刚好铺满网格)的方案数。

因为放横着的矩形时拓展的方向是横向的,就是说我们放矩形时,当前放的这个矩形只影响到下一列,这启示我们将“列号”作为 dp 的阶段,同时由于上一列的放置情况会影响到当前这一列,所以我们需要将上一列伸出来的部分作为状态中的一维才能转移。

那么如何表示上一列那些地方伸出来了呢?

如果用 bool 数组来表示第 \(i\) 行有没有伸出来,不仅效率低下,而且不方便计算,这时候状态压缩就来了:采用二进制压缩,相当于将原来的 bool 数组变成一个二进制数 \(state\),\(state\) 的第 \(i\) 位表示第 \(i\) 是否伸出,\(0\) 表示未伸出,\(1\) 表示伸出。

设 \(f(i, state)\) 表示已经摆完了前 \(i - 1\) 列,且从第 \(i - 1\) 列伸到第 \(i\) 列的方案数,那么状态转移方程为:

\[f(i, state) = \sum f(i - 1, last\_state) \]

其中 \(last\_state\) 是第 \(i - 2\) 列伸到第 \(i - 1\) 的状态,且需要满足 \(last\_state\) 对于 \(state\) 合法。

\(last\_state\) 对于 \(state\) 合法当且仅当以下两个条件满足:

  1. \(state \wedge last\_state = 0\),即第 \(i - 2\) 列伸到第 \(i - 1\) 的小方格和 \(i - 1\) 列放置的小方格不重复;
  2. 每一列,所有连续着空着的小方格必须是偶数个,因为竖着的矩形必须要能嵌入。

初始化: \(f(0,0) = 1\)。

按定义这里是:前第 \(-1\) 列都摆好,且从第 \(-1\) 列到第 \(0\) 列伸出来的状态为 \(0\) 的方案数。
首先,这里没有 \(-1\) 列,最少也是 \(0\) 列。
其次,没有伸出来,即没有横着摆的。即这里第 \(0\) 列只有竖着摆这 \(1\) 种状态。

目标: \(f(m,0)\)。

\(f(m, 0)\) 表示前 \(m - 1\) 列都处理完,并且第 \(m - 1\) 列没有伸出来的所有方案数。
即整个棋盘处理完的方案数。

再用集合划分的思想来解释一下。

首先要 “化零为整”,即用一个集合表示一类情况,对于这道题,假设我们放矩形时是对于每列都从上往下放,那么可以根据当前放到了第几列来划分集合

但这样划分我们无法找到各个集合之间的转移关系,所以还要再划分一次。

集合划分的依据就是寻找集合中元素的不同点,发现在摆完前 \(i - 1\) 列的方案中向第 \(i\) 列伸出的情况不同,所以可以以此来划分。

所以状态表示为:\(f(i, state)\) 表示已经摆完了前 \(i - 1\) 列,且从第 \(i - 1\) 列伸到第 \(i\) 列的方案数。

接着就是 “化整为零” 的过程,即状态计算,同上。

\(\texttt{Code:}\)

#include <vector>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 12, M = 1 << N;
typedef long long ll;
int n, m;
vector<int> tran[M];
ll dp[N][M];
bool st[M];

bool check(int x) { //判断该状态是否满足所有连续着空着的小方格必须是偶数个
    int cnt = 0;
    for(int i = 0; i < n; i++) {
        if(x >> i & 1) {
            if(cnt & 1) return false;
            cnt = 0;
        }
        else ++cnt;
    }
    if(cnt & 1) return false;
    return true;
}

int main() {
    while(scanf("%d%d", &n, &m), n || m) {
        for(int i = 0; i < 1 << n; i++) st[i] = check(i); //提前预处理那哪些状态是合法的
        
        for(int i = 0; i < 1 << n; i++) {
            tran[i].clear();  //多测清空
            for(int j = 0; j < 1 << n; j++)
                if(!(i & j) && st[i | j])
                    tran[i].push_back(j); //提前预处理出每个可行状态能由那些状态转移过来
        }
        
        memset(dp, 0, sizeof dp);
        dp[0][0] = 1;
        for(int i = 1; i <= m; i++)
            for(int j = 0; j < 1 << n; j++)
                for(int k = 0; k < tran[j].size(); k++)
                    dp[i][j] += dp[i - 1][tran[j][k]];
        printf("%lld\n", dp[m][0]);
    }
    return 0;
}

标签:cnt,last,int,Mondriaan,伸出,state,P10975,矩形,Dream
From: https://www.cnblogs.com/Brilliant11001/p/18386601

相关文章

  • BanG Dream! It's MyGO!!!!!
    BanGDream!It'sMyGO!!!!!题目描述在“BanGDream!It'sMyGO!!!”的世界里,各个乐团的演出和排练场地像星星一样被连接在一起,形成了一张美丽的网络图。每个乐团都有自己独特的演出场地和练习室,这些地点通过各种路径互相连接,组成了一张复杂的图谱。koala作为一名热爱音乐的乐......
  • dreambooth代码阅读
    网上dreambooth大部分只是对论文讲解,但代码讲解不是找不到就是收费,没办法,自己硬读,记录一下。水平不高,学机器学习不久,可能有错,欢迎指正,仅做参考。Dreambooth流程简单来说是1,通过在现有的Diffusion模型增加一个你要的token,变成一个新的模型,比如你给特定一只sys狗的照片训练,你新......
  • 推动视觉AI边界,智象未来HiDream荣登全球技术先锋榜单
    近日,世界经济论坛“全球技术先锋”荣誉榜单正式揭晓,智象未来HiDream凭借尖端技术成就入选。智象未来HiDream成立于2023年3月,是一家专注于多模态AIGC技术应用的公司,由加拿大工程院外籍院士IEEE/IAPR/CAAIFellow梅涛博士创立。回顾过往,众多知名企业,如Airbnb、Google、Tw......
  • HiDream引领图像文字嵌入技术新革命,助力多领域创意升级
    近日,HiDream“智象大模型2.0”正式上线!据官方信息显示,"智象大模型2.0"在处理文本、图像、视频以及3D内容的多模态能力上取得了显著进展。特别是在"文生图"领域,该模型实现了对长文本复杂逻辑的深入理解、图片与文字的精准嵌入,以及画面艺术感的充分展现,从而在三个关键维度上提升......
  • Living-Dream 系列笔记 第76期
    UVA1328简单题。我们有结论:对于一个周期串S的子串T,它的最小循环节即为T-nxt_{\left|T\right|}。(具体请查阅往期笔记)于是,我们枚举所有前缀,检验上式是否能被当前前缀的长度整除并且不止一个循环节即可。code#include<bits/stdc++.h>usingnamespacestd;constintN=......
  • Dreamforce '24重磅来袭!年度盛会将有何惊喜?
     作为Salesforce的旗舰会议,Dreamforce的历史已有20余年之久,是生态系统中的年度亮点。现如今,Dreamforce已经适应了线上受众的需求,通过Salesforce+提供直播和点播的参与方式。 近期,Salesforce宣布Dreamforce'24将于9月17日-19日举行,一年一度的科技盛会又要开始 Dreamforce......
  • Dreamweaver (DW)2021 下载 安装
    将 Dreamweaver2021 压缩包解压到本地:点击蓝色字体下载压缩包提取码ixsu鼠标右键点击 Set-up 选择 以管理员身份运行:点击 更改位置 可以自定义选择安装路径 也可以选择默认位置点击 继续:等待安装正常等待5分钟左右:安装完成点击关闭:双击桌面 Drea......
  • Living-Dream 系列笔记 第75期
    CF126B朴素解法:求出原字符串的最长border,并kmp匹配出出现在中间的最长border,若没有则不断缩短border的长度,直到中间存在。若border长度减到了\(0\),则无解。我们通过画图来探索优化方式。如图,蓝色部分为原串的最长border,红色部分为蓝色部分的最长border。容易发现,......
  • Living-Dream 系列笔记 第74期
    Kobe-Morris-Pratt算法定义一些基本定义:border:是一个字符串的子串(不与其本身相同)且满足既是其前缀又是其后缀的字符串,我们称之为该字符串的一个border。Kobe-Morris-Pratt算法(以下简称KMP算法),是解决字符串匹配问题的一种算法,实际做题中常偏思维,通常用到的只有其中的bo......
  • Living-Dream 系列笔记 第71期
    众所周知,换根dp是非常套路的。换根真好玩(换根dp:当不同节点作为根时,dp结果不一致,若枚举每个节点作为根,则时间复杂度过高,在此种情形下,可使用换根dp处理相邻两节点间的贡献,从而达到快速换根的效果。使用场景:对于一棵树,寻找以某节点\(u\)为根时取得的最大值/最小值......