[APIO2022] 火星

题解

容易发现这个操作相当于每次把地图的行列缩小两格,然后你需要把一些有用的信息保留在剩下的格子里,使得最后能够得到连通块个数。

每次操作的位置和轮数是已知的,但是我们只能把信息存到矩阵中,这是一道很有水平的通信题。

首先我们可以想到一种思路,就是用当前矩阵的右下角 (m,m)(m,m)(m,m) 记录矩阵 (m,m)∼(n,n)(m,m)\sim(n,n)(m,m)∼(n,n) 的信息,右下边界上的点记录一行或一列的信息:

然后每一轮我们只需要关注边界上的信息的转移,其它地方保持原数据不变,这样就能使处理的次数降维,为信息转移的部分留下足够暴力的实现可能。

首先右下边界上的信息是很好维护的,由于每个位置可记录 100bit 信息,而矩阵边长最多 41,可以直接记录一行或一列的 01 串。

重点是这个矩形内信息的维护。首先直接把整个 01 矩阵信息记录下来是不现实的,只能得很少的分。由于我们最终目的是得到连通块个数,所以可以想到类似插头 DP 的处理方法:记录矩阵内连通块个数,并记录边界线上的连通状况,然后就可以往左上添行或列转移。

连通块个数很少,所以硬塞进字符串中某个位置即可;困难的是边界线的连通状况,我们无法直接记录下包含 01 串以及连通性的所有信息。插头DP中根据状态数少的性质使用了重标号,但是这里显然没有留给我们充足的重标号时间,况且状态数还非常多。

我们只能用一种可以直接读取的压缩方式存下这个信息。

注意到除了 (m,m)(m,m)(m,m) 这个点,其它位置存的信息都好少哦。即便是右下边界,也只使用了一半空间,还可以压榨。我们不妨让其它位置分担一下储存信息的任务:右下边界上的点额外储存一行或一列的 01 串信息。正好 (m−1,m)(m-1,m)(m−1,m) 处和 (m,m−1)(m,m-1)(m,m−1) 处能够收集到矩形边界线的 01 串信息,那么就可以通过这两个点的信息还原边界线的01串。

剩下需要存进 (m,m)(m,m)(m,m) 的信息就只剩连通性了。插头 DP 里的一类经典结论,即边界线上连通的集合只会包含不会相交,就有点类似括号序列。
我们单独考虑边界线上的每一个 1 的连续段,它可能处于一个连通块的开头、中间、结尾,也可能单独为一个连通块,总情况数少于 4cnt4^{cnt}4cnt(cntcntcnt 表示连续段个数)。

把这些信息存下来过后,我们发现可以用类似括号匹配的方法,用栈来唯一地还原出每个连通块。什么情况下入栈出栈,什么时候与前面连通块连通,稍微想一下细节就能实现。
即使是长度 2n2n2n 的边界线,1的连续段个数也是不超过 nnn 的,所以 100bit 完全存的下来。

从复杂度大概是 O(n3)∼O(n4)O(n^3)\sim O(n^4)O(n3)∼O(n4) 吧,每个位置用得最多的也才不到 90bit,感觉限制给得挺松的。

代码

#incluve "mars.h" //JZM yyds!!
using namespace std;
using lll = __int128;
const lll E=1;
const int MAXN=114514;
lll getlll(const string&s){lll res=0;for(int i=0;i<100;i++)res^=(E*(s[i]^48)<<i);return res;
}
string getstr(const lll&a){string s="";for(int i=0;i<100;i++)s+=char(((a>>i)&1)^48);return s;
}int fa[MAXN],id[233][233],sk[MAXN],cnt[MAXN],lk;
bool s[233][233],d[MAXN];
int finds(int x){   //用并查集处理稍微方便一点return !fa[x]?x:(fa[x]=finds(fa[x]));
}
bool unions(int u,int v){u=finds(u),v=finds(v);if(u^v)return fa[v]=u,1;return 0;
}string process(vector <vector<string> > a, int i, int j, int k, int n)
{int m=((n-k-1)<<1),le=3+(k<<1);if(i<m&&j<m)return a[0][0];if(i<m){if(!k){string s(100,'0');s[0]=a[0][0][0],s[1]=a[0][1][0],s[2]=a[0][2][0];s[3]=a[1][0][0],s[4]=a[1][1][0],s[5]=a[1][2][0];return s;}lll x=getlll(a[0][2]),y=x>>(le-2);x&=(E<<(le-2))-1;x=(x<<1|(a[0][1][0]^48)),x=(x<<1|(a[0][0][0]^48));y=(y<<1|(a[1][1][0]^48)),y=(y<<1|(a[1][0][0]^48));return getstr(x^(y<<le));}if(j<m){if(!k){string s(100,'0');s[0]=a[0][0][0],s[1]=a[1][0][0],s[2]=a[2][0][0];s[3]=a[0][1][0],s[4]=a[1][1][0],s[5]=a[2][1][0];return s;}lll x=getlll(a[2][0]),y=x>>(le-2);x&=(E<<(le-2))-1;x=(x<<1|(a[1][0][0]^48)),x=(x<<1|(a[0][0][0]^48));y=(y<<1|(a[1][1][0]^48)),y=(y<<1|(a[0][1][0]^48));return getstr(x^(y<<le));}lll f=getlll(a[2][2]);int sum=f&65535,lm=(le<<1)-5,IN=0;f>>=16;                            //这里直接给了16位存连通块数,豪吧lll ln1=getlll(a[2][1])>>(le-2),ln2=getlll(a[1][2])>>(le-2);for(int i=0;i<2;i++)for(int j=0;j<2;j++)s[i][j]=(a[i][j][0]^48);for(int i=0;i<le-2;i++)s[2+i][2]=((ln1>>i)&1);for(int i=0;i<le-2;i++)s[2+i][1]=(a[2][1][i]^48);for(int i=0;i<le-2;i++)s[2+i][0]=(a[2][0][i]^48);for(int i=0;i<le-2;i++)s[2][2+i]=((ln2>>i)&1);for(int i=0;i<le-2;i++)s[1][2+i]=(a[1][2][i]^48);for(int i=0;i<le-2;i++)s[0][2+i]=(a[0][2][i]^48);if(!k){for(int i=0;i<3;i++)for(int j=0;j<3;j++)s[i][j]=(a[i][j][0]^48);sum=s[2][2],f=3;}for(int i=0;i<le;i++)for(int j=0;j<le;j++){if(i>2&&j>2)break;id[i][j]=++IN,d[IN]=s[i][j],fa[IN]=0;}vector<int>b;for(int i=le-1;i>1;i--)b.push_back(id[i][2]);for(int i=3;i<le;i++)b.push_back(id[2][i]);lk=0;for(int i=0,j;i<lm;i=j+1){int x=b[i];if(!d[x]){j=i;continue;}for(j=i;j<lm-1&&d[b[j+1]];j++)unions(b[j],b[j+1]);int ty=f&3;f>>=2;if(ty==0)sk[++lk]=x;else if(ty==1)unions(sk[lk],x);else if(ty==2)unions(sk[lk],x),lk--;}for(int i=0;i<le;i++)for(int j=0;j<le;j++){if(i>1&&j>1)break;sum+=s[i][j];}for(int i=0;i<le-1;i++)for(int j=0;j<le;j++){if(i>1&&j>1)break;if(s[i][j]&&s[i+1][j])sum-=unions(id[i][j],id[i+1][j]);}for(int i=0;i<le;i++)for(int j=0;j<le-1;j++){if(i>1&&j>1)break;if(s[i][j]&&s[i][j+1])sum-=unions(id[i][j],id[i][j+1]);}b.clear();for(int i=le-1;i>=0;i--)b.push_back(id[i][0]);for(int i=1;i<le;i++)b.push_back(id[0][i]);lm=b.size();for(int i=0;i<=IN;i++)cnt[i]=0;for(int x:b)cnt[finds(x)]++;lk=0,f=0;lll mi=1;for(int i=0,j;i<lm;i=j+1){int x=b[i];if(!d[x]){j=i;continue;}for(j=i;j<lm-1&&d[b[j+1]];j++);if(!lk||finds(sk[lk])!=finds(x)){sk[++lk]=x,cnt[finds(x)]-=j-i+1;if(!cnt[finds(x)])f+=mi*3,lk--;}else{cnt[finds(x)]-=j-i+1,f+=mi;if(!cnt[finds(x)])f+=mi,lk--;}mi<<=2;}return k==n-1?getstr(sum):getstr(f<<16|sum);
}

[APIO2022] 火星——构造、状态压缩相关推荐

  1. 0x56. 动态规划 - 状态压缩DP(习题详解 × 7)

    目录 Problem A. 最短Hamilton路径 ProblemB. 蒙德里安的梦想 Problem C. Corn Fields Problem D. 小国王 Problem E. 炮兵阵地 P ...

  2. 状态压缩DP AcWing算法提高课 (详解)

    基础课的状态压缩点这里 基础课中 蒙德里安的梦想 属于 棋盘式状态压缩dp,最短Hamilton路径 属于 集合状态压缩dp 1064. 小国王(棋盘式/基于连通性) 这种棋盘放置类问题,在没有事先知 ...

  3. CodeForces - 1288D Minimax Problem(二分+状态压缩)

    题目链接:点击查看 题目大意:给出一个n*m的矩阵,我们用maze[n][m]来表示每一个元素,现在我们需要选出其中 i 和 j 两行,i 和 j 可以相同,用这两行的元素构成一个新的数组a,构造规则 ...

  4. 洛谷 P-4045 密码(AC自动机+状态压缩+数位DP+乱搞)

    洛谷 P-4045 密码 记AC的第一道黑题! 题意:已知一段密码包含了一些字符串,然后求满足条件的密码有多少个,数量小于42时还得全部输出 思路: 一开始WA了两个点,不知道WA的什么,索性把读入的 ...

  5. LeetCode第 57 场力扣夜喵双周赛(差分数组、单调栈) and 第 251 场力扣周赛(状态压缩动规,树的序列化,树哈希,字典树)

    LeetCode第 57 场力扣夜喵双周赛 离knight勋章越来越近,不过水平没有丝毫涨进 1941. 检查是否所有字符出现次数相同 题目描述 给你一个字符串 s ,如果 s 是一个 好 字符串,请 ...

  6. 状态压缩动态规划部分习题详解

    状态压缩动态规划部分习题详解 状压DP部分题目详解 状态压缩动态规划部分习题详解 简介 经典子集类问题 原子弹 最短路与状压DP结合 送礼物 P3959宝藏 旅游 经典网格类 铺地砖 一笔画 其他类型 ...

  7. 1542. 找出最长的超赞子字符串 哈希+状态压缩

    1542. 找出最长的超赞子字符串 给你一个字符串 s .请返回 s 中最长的 超赞子字符串 的长度. 「超赞子字符串」需满足满足下述两个条件: 该字符串是 s 的一个非空子字符串 进行任意次数的字符 ...

  8. 【AcWing】数位统计DP、树形DP、状态压缩DP、记忆化搜索

    [AcWing]数位统计DP.树形DP.状态压缩DP.记忆化搜索 一.数位统计DP 二.状态压缩DP 三.树形DP 四.记忆化搜索 一.数位统计DP 计数问题 给定两个整数 a 和 b,求 a 和 b ...

  9. pat 食物链(状态压缩求哈密顿回路)

    状态压缩求哈密顿回路 #include<bits/stdc++.h> using namespace std; bool dp[23][1<<21]; char s[22][2 ...

最新文章

  1. Mxnet TensorRT
  2. SQL表内查重和删重
  3. python核心编程电子版_python核心编程答案.pdf
  4. 使用matlab编译器生成EXE文件
  5. python类似微信未读信息图片脚本
  6. 【MyBatis框架】配置文件-resultMap总结
  7. Hive数据据类型 DDL DML
  8. 简述什么是图灵机_什么是图灵机
  9. 2013年想学的东西。。。
  10. 服务器cpu最多几核心,决定虚拟服务器所需要的CPU核心数量是一件非常复杂的事情...
  11. ip-guard网页浏览放开微信二维码和QQ截图
  12. 按键精灵+屏幕录像专家实现数据抓包录制
  13. java一寸是多少像素_一寸照片的尺寸是多少像素
  14. 输入英文句子,导出英语单词个数和英文字母个数 Python
  15. 超强大的数学计算器——WolframAlpha(含安卓下载连接)
  16. win10系统1903版本设置默认英文输入法
  17. ENVI制作土壤干旱墒情专题图/地域干旱分布
  18. Linux网络编程之获取网络天气信息
  19. 商城运费模板数据库简单设计思路
  20. 《OpenDRIVE1.6规格文档》5

热门文章

  1. vue e2e 测试
  2. BMS系统—产生原因如何工作
  3. 记录Docker安装Mysql容器,及其数据卷的配置
  4. 关于发布《深圳市培育发展生物医药产业集群行动计划(2022-2025年)》的通知
  5. python自动更新excel_Python办公自动化(六)|自动更新表格,告别繁琐
  6. SQLite(一):初探
  7. WM_WINDOWPOSCHANGING 消息
  8. Windows实时运动控制软核(一):LOCAL高速接口测试之C#
  9. 谷歌浏览器导出书签方法
  10. 一个.net6简单的图片上传(文件也可用)