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, ...
随机推荐
- SharkCTF2021 BabyGame
web类题. 访问题给页面,页面里没啥信息.抓包,发现: 访问它,发现是一个游戏. F12之后看调试器里的js代码,发现: console.log("balabalabala"); ...
- 代码混淆保安全「GitHub 热点速览 v.21.43」
作者:HelloGitHub-小鱼干 虽然让代码难以阅读看似是件难以理解的事情,但是混淆后的代码起到了类似加密的作用,而且经过混淆的代码依旧能实现原代码的功能.javascript-obfuscato ...
- Codeforces1573B
### 问题描述 - 给你两个数组,a数组里面是1 - 2n中的奇数任意顺序排列组成,b数组里面是1 - 2n中的奇数任意顺序排列组成. - 问你最少需要多少次操作能让a的字典序小于b. ### 思路 ...
- (五)、Docker 容器数据卷
1.什么是数据卷 将运用与运行的环境打包形成容器运行 ,运行可以伴随着容器,但是我们对数据的要求希望是持久化的 容器之间希望有可能共享数据 Docker容器产生的数据,如果不通过docker comm ...
- sum-root-to-leaf-numbers leetcode C++
Given a binary tree containing digits from0-9only, each root-to-leaf path could represent a number. ...
- 2021CCPC华为云挑战赛 部分题题解
CDN流量调度问题 题看了没多久就看出来是\(DP\)的题,然后就设了状态\(f[i][j]\)表示到前\(i\)个点时已经用了\(j\)个节点的最小总代价,结果发现转移时\(O(nm^2)\),但这 ...
- SI Macro
获取 buf 里的 symbol cbuf = BufListCount() msg(cbuf) ibuf = 0 while (ibuf < cbuf) { hbuf = BufListIte ...
- Flink入门-第一篇:Flink基础概念以及竞品对比
Flink入门-第一篇:Flink基础概念以及竞品对比 Flink介绍 截止2021年10月Flink最新的稳定版本已经发展到1.14.0 Flink起源于一个名为Stratosphere的研究项目主 ...
- springcloud优雅停止上下线与熔断
SpringCloud 服务优雅上下线 Spring Boot 框架使用"约定大于配置"的特性,优雅流畅的开发过程,应用部署启动方式也很优雅.但是我们通常使用的停止应用的方式是 k ...
- k8s入坑之路(13)kubernetes重要资源(namespace隔离 resources资源管理 label)
Namespace --- 集群的共享与隔离 语言中namespace概念 namespace核心作用隔离 以上是隔离的代码.namespace隔离的是: 1.资源对象的隔离:Service.Depl ...