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, ...
随机推荐
- 【UE4】GAMES101 图形学作业0:矩阵初识
作业描述 给定一个点P=(2,1), 将该点绕原点先逆时针旋转45◦,再平移(1,2), 计算出变换后点的坐标(要求用齐次坐标进行计算). UE4 知识点 主要矩阵 FMatrix FBasisVec ...
- OO--第三单元规格化设计 博客作业
OO--第三单元规格化设计 博客作业 前言 第三单元,我们以JML为基础,先后完成了 PathContainer -> Graph -> RailwaySystem 这是一个递进的过程,代 ...
- Linux中检查字符串是否为合法IP地址的shell脚本
#!/bin/bash #判断IP地址是否为有效IP CHKECK_IP () { CHECK_STEP1=`echo $1 | awk -F"." '{print NF}'` i ...
- 并发编程从零开始(六)-BlockingDeque+CopyOnWrite
并发编程从零开始(六)-BlockingDeque+CopyOnWrite 5.2 BlockingDeque BlockingDeque定义了一个阻塞的双端队列接口: 该接口继承了BlockingQ ...
- logstash收集的日志输出到elasticsearch中
logstash收集的日志输出到elasticsearch中 一.需求 二.实现步骤 1.编写pipeline文件 1.`elasticsearch`配置参数解析: 2.可能会报的一个异常 2.准备测 ...
- 如何理解Stand SPI Dual SPI 和Quad SPI??
1.首先看一下接口 Standard SPI: CLK, /CS, DI, DO, /WP, /Hold Dual SPI: CLK, /CS, IO0, IO1, /WP, /Hold Quad S ...
- 攻防世界 web3.backup
如果网站存在备份文件,常见的备份文件后缀名有:.git ..svn..swp..~..bak..bash_history..bkf尝试在URL后面,依次输入常见的文件备份扩展名. ip/index.p ...
- 【Azure 应用服务】App Service For Linux 部署Java Spring Boot应用后,查看日志文件时的疑惑
编写Java Spring Boot应用,通过配置logging.path路径把日志输出在指定的文件夹中. 第一步:通过VS Code创建一个空的Spring Boot项目 第二步:在applicat ...
- Android DataBinding使用详解
简介 DataBinding是一个自动绑定UI的框架. 使用DataBinding需要在app根目录的build.gradle文件中加入DataBinding配置: android { .... da ...
- Arthas在线java进程诊断工具 在线调试神器
tag: java 诊断 堆栈 在线调试 耗时 死锁 arthas 阿里巴巴 Arthas (阿尔萨斯) Arthas 是 Alibaba 开源的Java诊断工具,深受开发者喜爱. 官网文档:http ...