AT695 マス目
本题选自 DP 优化方法大杂烩 状压部分。
这个题很 nb。下文记 \(n=H\),\(m=W\)。
对于每一列,如果只记录一个格子是否为黑色,那么发现它无法处理从右边绕到左边再绕回去的路径,GG。
改变一下思路,注意到一列最多会产生三个连通块,那么我们用一个长度为 \(n\) 的四进制数表示联通状态。某一位为 \(0\) 表示白格子,为 \(1\) 表示能和 \((1,1)\) 联通,为 \(2\) 表示在某个不与 \((1,1)\) 联通的联通块中,为 \(3\) 表示在某个不与 \((1,1)\) 和状态 \(2\) 所表示的联通块联通的连通块中。一个状态合法,当且仅当两个相邻的不为 \(0\) 的位相同且至少存在一位为 \(1\) 。再观察到连通块 \(2,3\) 其实是等价的,即它们之间无序,所以钦定如果出现了 \(3\),那么在其之前的某一位一定出现了 \(2\)。转移时 \(2^n\) 枚举下一列的黑白状态,用并查集维护连通性,再更新出下一列表示联通状态的四进制数,判断是否合法并转移即可,时间复杂度 \(m8^n\)。最终答案即为 \(f_{n,c}\),其中 \(c\) 为所有合法且第 \(n\) 位为 \(1\) 的四进制数。
在上述限制下,其实满足条件的状态很少。暴力枚举可知 \(n=6\) 时一列合法的状态总数只有 \(S_6=196\),所以我们可以将其离散化。这样时间复杂度被优化到 \(mS_n2^n\log n\),其中 \(\log\) 是并查集的复杂度(其实基本上可以忽略不计了)。
注意到对于一个合法的联通状态,它根据下一列的黑白状态所能转移到的联通状态是固定的,即不随列数的变化而改变,因此可以 \(S_n2^n\log n\) 预处理出来每个联通状态在知道下一列的黑白状态时所转移到的下一列联通状态,时间复杂度被再一次优化到 \(mS_n2^n\),其中 \(S_n\) 只有不到 \(200\),是一个非常优秀的算法,同时也拿到了本题的最优解(2021.7.9)。
理论上本题的 \(m\) 可以出到 \(10^9\) 级别,因为矩阵快速幂可以做到 \(S_n^3\log m\)。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mem(x,v) memset(x,v,sizeof(x))
#define mcpy(x,y) memcpy(x,y,sizeof(y))
const int N=200;
const int mod=1e9+7;
int n,m,cnt,ans,t[N],g[N],tr[N][64],ed[N];
int c[6],buc[4],f[12],mp[4096];
void add(int &x,int y){x=(x+y)%mod;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void merge(int u,int v){
u=find(u),v=find(v);
if(u!=v)f[v]=u;
}
int main(){
cin>>n>>m;
for(int i=1;i<1<<(2*n);i++,mem(buc,0)){
for(int j=0;j<n;j++)c[j]=i>>(j*2)&3,buc[c[j]]=1;
if(!buc[1])continue;
if(buc[3]&&!buc[2])continue;
bool judge=1;
for(int j=1;j<n;j++)if(c[j-1]&&c[j]&&c[j-1]!=c[j])judge=0;
for(int j=0,ap=0;j<n;j++)
if(c[j]==2)break;
else if(buc[3]&&c[j]==3)judge=0;
if(!judge)continue;
mp[i]=++cnt;
if((i>>(2*n-2)&3)==1)ed[cnt]=1;
g[cnt]=(i&3)==1;
for(int j=0;j<n;j++)
for(int k=j+1;k<n;k++)
if(c[j]==c[k]&&c[j])
for(int l=j+1;l<k;l++)
if(c[l]!=c[j])
g[cnt]=0;
for(int j=1;j<1<<n;j++){
for(int k=0;k<2*n;k++)f[k]=k;
for(int k=1;k<4;k++)
for(int l=0,pre=-1;l<n;l++)
if(c[l]==k){
if(~pre)merge(l,pre);
pre=l;
}
for(int k=0;k<n;k++){
if(c[k]&&(j>>k&1))merge(k,k+n);
if(k&&(j>>k&1)&&(j>>(k-1)&1))merge(k+n-1,k+n);
}
int one,legal=0,two=-1,msk=0;
for(int k=0;k<n;k++)if(c[k]==1){one=find(k); break;}
for(int k=0;k<n;k++)
if(j>>k&1){
int f=find(k+n);
if(f==one)msk+=1<<(2*k),legal=1;
else if(two==-1||f==two)two=f,msk+=2<<(2*k);
else msk+=3<<(2*k);
}
if(legal)tr[cnt][j]=msk;
}
}
for(int i=1;i<=cnt;i++)
for(int j=0;j<1<<n;j++)
tr[i][j]=mp[tr[i][j]];
for(int i=1;i<m;i++){
mcpy(t,g),mem(g,0);
for(int j=1;j<=cnt;j++)
for(int k=1;k<1<<n;k++)
if(tr[j][k])
add(g[tr[j][k]],t[j]);
}
for(int i=1;i<=cnt;i++)if(ed[i])add(ans,g[i]);
cout<<ans<<endl;
return 0;
}
AT695 マス目的更多相关文章
- DP 优化方法大杂烩 & 做题记录 I.
标 * 的是推荐阅读的部分 / 做的题目. 1. 动态 DP(DDP)算法简介 动态动态规划. 以 P4719 为例讲一讲 ddp: 1.1. 树剖解法 如果没有修改操作,那么可以设计出 DP 方案 ...
- ng-class结合三目运算
ng-class文档:https://docs.angularjs.org/api/ng/directive/ngClass 但是在实际项目中可能会用到三目运算,实例如下: <ul> &l ...
- Objective-C中的类目,延展,协议
Objective-C中的类目(Category),延展(Extension),协议(Protocol)这些名词看起来挺牛的,瞬间感觉OC好高大上.在其他OOP语言中就没见过这些名词,刚看到这三个名词 ...
- 项 目 管 理 知 识 体 系 指 南 (PMBOK2008)
项 目 管 理 知 识 体 系 指 南 (第4版) PMBOK2008 输入 工具与技术 输出 4.项目整合管理 4.1 制定项目章程 4.1.1.1 项目工作说明书 4.1.2.1 专家判断 4.1 ...
- Scrapy003-项目流程
Scrapy003-项目流程 @(Spider)[POSTS] 前两篇文章我们了解到Scrapy的原理和安装的相关知识,这节就需要知道创建项目流程的小知识. 根据官方文档:http://scrapy- ...
- OC中协议, 类目, 时间, 延展, 属性
只有继承和协议需要引IMPORT "头文件"; 必须接受marryprotocol协议, id<marryprotocol>基于类型的限定, 才能给实例变量赋值 @pr ...
- angularjs的三目运算
前言:前几天写代码的时候遇到一个问题,有一个按钮,有"已关注"和"+关注"两种状态,需要对这两种状态的按钮的背景颜色进行区分,单后点击"已关注&quo ...
- Objective - C - 添加类目 - NSDate
1.类目为系统内部的类或者是没有源代码的类添加方法,不有添加实例变量 2.添加的方法会成为原类的一部分,子类照样可以使用 3.类目的文件名为原类名+文件名 4.既可以添加实例方法,也可以添加类方法 X ...
- 【Python全栈笔记】03 [模块二] 16-17 Oct Set 集合,三目运算
Set 集合 set - unordered collections of unique elements 创建一个set/一个空set # create a new set set1 = {1,2, ...
随机推荐
- pip 安装软件报 Requirement already satisfied
pip 安装的时候报错了,以为是豆瓣源有问题,换了还是一样,于是我们只需要加入一个参数 --target=路径 给它一个指定的位置就可以解决这个问题 安装位置不变,只是增加了一个参数在后面
- 求求你了,用Docker吧
这是一个开始使用 Docker 的 Tutorial 大无语事件发生!大数据课实验课要用到Hadoop,实验指导是在一个Ubuntu虚机上通过安装包安装Hadoop并运行一个词频统计程序,整个实验就是 ...
- 用例圖學習實例 / Learning Use Case Diagram by Examples
什麼是用例圖? 用例描述了一個演員和感興趣的系統之間的一系列交互,以達到某種特定目標,並由某種觸發事件引發.用例滿足需求或為演員解決問題.用例圖包含一組用例,可以通過從每個角色的不同角度講述系統將如何 ...
- kivy画板
from kivy.app import App from kivy.graphics import Line, Color # 引入绘图线条,颜色 from kivy.uix.widget impo ...
- 第七次Scrum Metting
日期:2021年5月5日 会议主要内容概述:前后端对接,以及接下来的测试优化等工作. 一.进度情况 组员 负责 两日内已完成的工作 后两日计划完成的工作 工作中遇到的困难 徐宇龙 后端 测试数据模块和 ...
- 攻防世界 杂项 7.Aesop_secret
打开发现是个gif,以为有个二维码扫一下就给flag,结果被欺骗.呜呜呜 好了,还是使用编辑器看一下吧 发现了好玩的,U2FsdGVkX19QwGkcgD0fTjZxgijRzQOGbCWALh4sR ...
- Ubuntu用apt安装MySQL
这里以MySQL5.7为例. # 如果之前有安装旧版,先移除sudo apt-get --purge remove mysql-server mysql-client mysql-common # 安 ...
- Openeuler安装完整man手册
Openeuler安装完整man手册 在 Debian 和 Ubuntu 中安装了Shell 前端软件包管理器apt(Advanced Packaging Tool),可以通过如下方式安装. ...
- 【数据结构&算法】04-线性表
目录 前言 线性表的定义 线性表的数据类型&操作 线性表操作 数据类型定义 复杂操作 线性表的顺序存储结构 顺序存储结构的定义 顺序存储方式 数据长度和线性表长度的区别 地址的计算方法 顺序存 ...
- Linux&C open creat read write lseek 函数用法总结
一:五个函数的参数以及返回值. 函数 参数 返回值 open (文件名,打开方式以及读 ...