洛谷题面传送门

介绍一个不太主流的、非常暴力的做法(

首先注意到 \(n\) 非常小,\(m\) 比较大,因此显然以列为阶段,对行的状态进行状压。因此我们可以非常自然地想到一个非常 trivial 的做法:\(dp_{i,mask1,mask2}\) 表示考虑到第 \(i\) 列,当前列状态为 \(mask1\),当前列中能从左上角到达的点集为 \(mask2\),枚举下一列状态简单转移一下即可。

但是相信聪明的读者到这里一定可以发现,这个做法是错误的,因为题目规定可以朝四个方向走,也就是说有可能出现如下图所示的情况:

对于下图中的情况,当我们状态转移到第四列时,我们会判定 \(1,2,3,4\) 行是可以从起点到达的,而由于前一列(第 \(3\) 列)的第 \(6\) 行在前三行组成的子矩形中无法从起点到达,因此我们也会判断第四列第 \(6\) 行无法从源点到达,也就导致了情况的漏算。

怎么处理呢?由于这种情况的存在,我们要在状态中多记录一些东西,注意到这个 \(n=6\) 有点小的出奇,\(\dbinom{6}{2}\) 不过 \(15\),因此考虑对每个点对 \((j,k)\) 记录当前列中这两行的格子在前 \(i\) 列组成的子矩形中是否连通,即设 \(dp_{i,j,k}\) 表示前 \(i\) 列中两两可达性为 \(j\),\(k\) 中的格子可以从 \((1,1)\) 到达的方案数。这样一来我们在枚举下一列状态并 check 每个点是否能从 \((1,1)\) 到达时可以考虑这样的做法:对于每个 \(j\),如果它左边的格子能从 \((1,1)\) 到达并且它是黑格,那么它能从 \((1,1)\) 到达,否则如果 \(\exists k\) 满足 \((j,k)\) 在前 \(i\) 列组成的子矩形中连通并且 \(k\) 能从 \((1,1)\) 到达,那么 \(j\) 能从 \((1,1)\) 到达,正确性显然。而显然如果我们知道了上一列的两两之间的可达性,是可以用传递闭包 or 并查集直接推出上一列的可达性的,因此这个做法恰好能够解决我们之前遇到的问题。

复杂度?最坏情况下该算法的复杂度可以达到 \(2^{15}\times 2^6\times 2^6\times 100\times 6^3\approx 3\times 10^{12}\)(这要是能过我就当场把这个电脑屏幕 **),然鹅这个复杂度是远远达不到上界的,因为首先对于这 \(2^{15}\) 个表示可达性的状态中,一个状态合法当且仅当它的传递闭包就是它本身,暴力枚举一下可知这 \(2^{15}\) 个状态中总共只有 \(203\) 个合法的状态,这下复杂度降到了 \(203\times 2^6\times 2^6\times 100\times 6^3\approx 2\times 10^{10}\),其次在 DP 过程中很多状态是转移不到的,因此如果某个 \(dp_{i,j,k}=0\) 那么我们就不用转移了,加上这个小小的优化之后速度又能快不少。此题 \(\text{TL}=8\text{s}\),而我这个做法只跑了 \(222\text{ms}\)。当然这肯定不是最快的版本,还有优化的空间,比方说一开始大可不必 \(\mathcal O(2^{15}\times 6^3)\) 枚举所有状态,可以一遍 DFS 一遍把不合法的状态剪掉,这样程序还可以跑得更快(虽然这不是复杂度瓶颈所在),以及在转移中,由于本题的图是无向图,传递闭包可以用 dsu 来代替,这样可将 \(6^3\) 变成 \(6^2\),但由于本人懒癌症晚期就没有进一步优化了(

const int MAXM=100;
const int MAXT=1<<6;
const int MAXP=1<<15;
const int MAX_ST=203;
const int MOD=1e9+7;
void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int n,m,id[MAXP+5],msk[MAXP+5],cnt=0,is[8][8],pre_is[8][8],blk[8];
int dp[MAXM+5][MAXT+5][MAX_ST+5];
int main(){
scanf("%d%d",&n,&m);int lim=1<<(n*(n-1)/2);
for(int i=0;i<lim;i++){
int cur=i;bool flg=1;
for(int j=1;j<=n;j++) for(int k=1;k<j;k++)
is[j][k]=is[k][j]=cur&1,cur>>=1;
for(int j=1;j<=n;j++) is[j][j]=1;
for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) for(int l=1;l<=n;l++)
if(is[j][k]&&is[k][l]&&!is[j][l]) flg=0;
if(flg) msk[++cnt]=i,id[i]=cnt;
} //printf("%d\n",cnt);
for(int i=0;i<(1<<n);i++){
if(~i&1) continue;
int pre=0,msk1=0,msk2=0;memset(is,0,sizeof(is));
for(int j=1;j<=n;j++){
if(~i>>(j-1)&1){
for(int k=pre+1;k<j;k++) for(int l=pre+1;l<k;l++) is[k][l]=is[l][k]=1;
if(!pre) for(int k=pre+1;k<j;k++) msk1|=(1<<k-1);
pre=j;
}
} if(!pre) msk1=(1<<n)-1;
for(int k=pre+1;k<=n;k++) for(int l=pre+1;l<k;l++) is[k][l]=1;
for(int k=n;k;k--) for(int l=k-1;l;l--) msk2=msk2<<1|is[k][l];
// printf("%d %d\n",msk1,msk2);
add(dp[1][msk1][id[msk2]],1);
}
for(int i=1;i<m;i++){
for(int j=1;j<(1<<n);j++){
for(int k=1;k<=cnt;k++){
// printf("%d %d %d %d\n",i,j,k,dp[i][j][k]);
if(!dp[i][j][k]) continue;int cur=msk[k];
for(int l=1;l<=n;l++) for(int o=1;o<l;o++)
pre_is[l][o]=pre_is[o][l]=cur&1,cur>>=1;
for(int l=0;l<(1<<n);l++){
for(int o=1;o<=n;o++) blk[o]=l>>(o-1)&1;
int pre=0;memset(is,0,sizeof(is));
for(int o=1;o<=n;o++){
if(!blk[o]){
for(int p=pre+1;p<o;p++) for(int q=pre+1;q<p;q++)
is[p][q]=is[q][p]=1;
pre=o;
}
}
for(int p=pre+1;p<=n;p++) for(int q=pre+1;q<p;q++)
is[p][q]=is[q][p]=1;
for(int p=1;p<=n;p++) if(blk[p])
for(int q=1;q<p;q++) if(blk[q])
is[p][q]|=pre_is[p][q],is[q][p]|=pre_is[q][p];
for(int p=1;p<=n;p++) if(blk[p])
for(int q=1;q<=n;q++) if(blk[q])
for(int r=1;r<=n;r++) if(blk[r])
is[q][r]|=is[q][p]&is[p][r];
int msk1=0,msk2=0;
for(int p=1;p<=n;p++){
bool flg=0;
if(blk[p]&&(j>>p-1&1)) flg=1;
else if(blk[p]){
for(int q=1;q<=n;q++) if(is[p][q]&&(j>>q-1&1))
flg=1;
} msk1|=flg<<(p-1);
}
for(int p=n;p;p--) for(int q=p-1;q;q--)
msk2=msk2<<1|is[p][q];
// printf("%d %d %d -> %d %d %d(%d)\n",i,j,msk[k],i+1,msk1,msk2,id[msk2]);
add(dp[i+1][msk1][id[msk2]],dp[i][j][k]);
}
}
}
} int ans=0;
for(int j=1;j<(1<<n);j++) if(j>>(n-1)&1)
for(int k=1;k<=cnt;k++) add(ans,dp[m][j][k]);
printf("%d\n",ans);
return 0;
}

Atcoder Typical DP Contest S - マス目(状压 dp+剪枝)的更多相关文章

  1. Atcoder Yet Another Palindrome Partitioning(状压dp)

    Atcoder Yet Another Palindrome Partitioning 思路: 一个字符串满足条件的情况是奇数字母个数小于等于1,也就是异或起来是1<<j(0<=j& ...

  2. CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

  3. Codeforces Gym 100610 Problem K. Kitchen Robot 状压DP

    Problem K. Kitchen Robot Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/10061 ...

  4. 状压dp入门

    状压dp的含义 在我们解决动态规划题目的时候,dp数组最重要的一维就是保存状态信息,但是有些题目它的具有dp的特性,并且状态较多,如果直接保存的可能需要三维甚至多维数组,这样在题目允许的内存下势必是开 ...

  5. [USACO06NOV]玉米田$Corn \ \ Fields$ (状压$DP$)

    #\(\mathcal{\color{red}{Description}}\) \(Link\) 农场主\(John\)新买了一块长方形的新牧场,这块牧场被划分成\(M\)行\(N\)列\((1 ≤ ...

  6. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

  7. dp,状压dp等 一些总结

    也就作业几题而已,分析一下提醒 最重要的就是,记住,没用的状态无论怎么转移最后都会是没用的状态,所以每次转移以后的有值的状态都是有用的状态. 几种思考方向: 第一种:枚举当前的状态,转移成另外一个状态 ...

  8. NOIP2016愤怒的小鸟 [状压dp]

    愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟, ...

  9. [Poj2411]Mondriaan's Dream(状压dp)(插头dp)

    Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18096   Accepted: 103 ...

  10. [bzoj3717][PA2014]Pakowanie_动态规划_状压dp

    Pakowanie bzoj-3717 PA-2014 题目大意:给你n个物品m个包,物品有体积包有容量,问装下这些物品最少用几个包. 注释:$1\le n\le 24$,$1\le m\le 100 ...

随机推荐

  1. 深度剖析Redis6的持久化机制(大量图片说明,简洁易懂)

    Redis的强劲性能很大程度上是由于它所有的数据都存储在内存中,当然如果redis重启或者服务器故障导致redis重启,所有存储在内存中的数据就会丢失.但是在某些情况下,我们希望Redis在重启后能够 ...

  2. WPF中的命令(Command)

    这节来讲一下WPF中的命令(Command)的使用. [认识Command] 我们之前说过,WPF本身就为我们提供了一个基础的MVVM框架,本节要讲的命令就是其中一环,通过在ViewModel中声明命 ...

  3. 【二食堂】Alpha - Scrum Meeting 4

    Scrum Meeting 4 例会时间:4.14 12:30 - 12:50 进度情况 组员 昨日进度 今日任务 李健 1. 主页面的搭建工作issue 1. 完成主页搭建**issue2. 与后端 ...

  4. VUE调用子窗口弹窗或组件弹窗,关闭弹窗刷新父级页面主页面,通过this.$emit来实现

    this.$emit是父级向自己传值 第一步在父级页面创建自己页面的引用 <template> <div> <edit ref="edit" @ref ...

  5. 『学了就忘』Linux基础 — 9、虚拟机中快照的使用

    目录 1.快照的含义 2.快照的使用 步骤一:创建拍摄快照 步骤二:填写快照信息并创建 步骤三:查看快照 步骤四:操作快照 3.管理虚拟机小技巧 4.关于快照说明 快照和克隆是VMware中两个非常实 ...

  6. 架构师之路-redis集群解析

    引子 上篇<架构师之路-https底层原理>里我提到了上面的整体视图,文章也介绍了想要真正能在工作中及时正确解决问题的基本功:原理理解透彻.今天以redis集群解析为例介绍一个及时敏锐的发 ...

  7. P2120 [ZJOI2007]仓库建设

    P2120 [ZJOI2007]仓库建设 怎么说呢?算是很水的题了吧... 只要不要一开始就把dp想错就行... #include<bits/stdc++.h> #define ll lo ...

  8. Android Jetpack Compose 引入示例工程

    引入 Jetpack Compose 示例工程 去GitHub上找到Compose的示例工程 https://github.com/android/compose-samples ,clone到本地 ...

  9. 二层组网AP上线

    一.实验目的 1)掌握配置WLAN源接口的命令 2)掌握配置DHCP服务器的命令 3)掌握手工确认AP上线的方法a 二.实验仪器设备及软件 仪器设备:一台AC,四台AP 软件:ENSP 三.实验原理 ...

  10. Can't open PID file /run/zabbix/zabbix_agentd.pid

    神奇的事情,重启主机(reboot)后查看状态是正常的没有报错,重启zabbix-agent后,报无法打开zabbix_agentd.pid,zabbix-web正常监控 1.首先,/etc/zabb ...