[CSP-S模拟测试]:连连看(图论+容斥)
题目传送门(内部题74)
输入格式
  输入文件$link.in$
  第一行三个整数$n,m,k$,之间用空格隔开,$n,m$表示地图行数和列数,$k$表示每个方块周围相邻的位置(至多有$4$个,至少有$2$个,在地图的角上就是$2$个,地图的边上就是$3$个,地图内部就是$4$个)中,最多有$k$个位置是空地。
  接下来$n$行,每行$m$个自然数,之间用空格隔开,描述地图。
输出格式
  输出文件$link.out$
  一行一个整数表示这一步有多少种选法。
样例
样例输入1:
1 3 1
1 1 1
样例输出1:
2
样例输入2:
2 3 1
0 0 0
1 1 1
样例输出2:
3
数据范围与提示
样例$1$解释:
  两种选法,$(x,y)$表示第$x$行第$y$列的方块
  第一种:$(1,1)$和$(1,2)$,第二种:$(1,2)$和$(1,3)$
  注意第$1$行第$1$列的方块和第$3$列的方块并不能连通。
样例$2$解释:
  三种选法,$(x,y)$表示第$x$行第$y$列的方块
  第一种:$(1,1)$和$(1,2)$,第二种:$(1,2)$和$(1,3)$,第三种:$(1,1)$和$(1,3)$
数据范围:
  对所有测试点,$n\leqslant 10^3,m\leqslant 10^3,k\in\{0,1,2,3,4\}$,地图中出现的数字都是$[0,10^6]$的整数。
  第$1$个测试点:$k=0$
  第$2,3,4$测试点:$n>1,m>1$,且只有满足横纵坐标均为奇数的位置才会有方块。
  也就是说,如果某个位置的横坐标或纵坐标是偶数,这个位置就是空地(数字$0$)。$k=4$。
  第$5,6,7$个测试点:$n\times m\leqslant 1,000,k=4$。
  第$8,9,10$个测试点:$k=1$
  第$11,12,13,14$个测试点:$k=2$
  第$15,16$个测试点:$k=3$
  第$17,18,19,20$个测试点:$k=4$
  第$8,11,12,15,17$个测试点还满足:$n=500,m=500$
  第$18$个测试点还满足:$n=700,m=700$
  如果担心输入时间过长,可以使用第二题给出的读入函数。
题解
相当有意思的一道题呢~
不妨设每一块全白为一个“空地极大联通块”。
再不妨设每两个不是空地的块之间也有一个“空地极大联通块”。
那么,挨着同一个“空地极大联通块”的相同颜色的就可以相互连线了。
但是显然不能直接统计每一个“空地极大联通块”,因为有可能出现如下图中的情况:
| 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
| 
 0  | 
 1  | 
 1  | 
 1  | 
 0  | 
 1  | 
 1  | 
 1  | 
 0  | 
| 
 0  | 
 1  | 
 0  | 
 0  | 
 1  | 
 0  | 
 0  | 
 1  | 
 0  | 
| 
 0  | 
 1  | 
 0  | 
 1  | 
 0  | 
 1  | 
 0  | 
 1  | 
 0  | 
| 
 0  | 
 1  | 
 0  | 
 0  | 
 1  | 
 0  | 
 0  | 
 1  | 
 0  | 
| 
 0  | 
 1  | 
 1  | 
 1  | 
 0  | 
 1  | 
 1  | 
 1  | 
 0  | 
| 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
 0  | 
会发现,可么可能有一对点同时属于多个“空地极大联通块”,但是不用担心,容斥一下就好了。
因为一个点最多属于$4$个“空地极大联通块”,所以状态数也不多。
于是可以设$f1[],f2[][],f3[][][],f4[][][][]$分别表示仅属于集合……的,属于集合……和……的,……
但是这样时间可空间都不允许。
考虑其实非$0$项并不多,于是可以仅存储这些非$0$项,然后排个序将一样的颜色排到一起就可以容斥啦。
时间复杂度:$\Theta(4\times 15\times n\times m)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec{int col,a[5];}e[15000001];
int n,m,k;
int Map[1001][1001],vis[1001][1001];
int gs[1001][1001][5],sum[1001][1001],gss,top;
long long ans,now=1;
void dfs(int x,int y)
{
if(x>1&&!vis[x-1][y])
if(!Map[x-1][y]){vis[x-1][y]=gss;dfs(x-1,y);}
else if(gs[x-1][y][sum[x-1][y]]!=gss)gs[x-1][y][++sum[x-1][y]]=gss;
if(x<n&&!vis[x+1][y])
if(!Map[x+1][y]){vis[x+1][y]=gss;dfs(x+1,y);}
else if(gs[x+1][y][sum[x+1][y]]!=gss)gs[x+1][y][++sum[x+1][y]]=gss;
if(y>1&&!vis[x][y-1])
if(!Map[x][y-1]){vis[x][y-1]=gss;dfs(x,y-1);}
else if(gs[x][y-1][sum[x][y-1]]!=gss)gs[x][y-1][++sum[x][y-1]]=gss;
if(y<m&&!vis[x][y+1])
if(!Map[x][y+1]){vis[x][y+1]=gss;dfs(x,y+1);}
else if(gs[x][y+1][sum[x][y+1]]!=gss)gs[x][y+1][++sum[x][y+1]]=gss;
}
bool cmp(rec a,rec b)
{
if(a.col!=b.col)return a.col<b.col;
for(int i=1;i<5;i++)
if(a.a[i]!=b.a[i])return a.a[i]<b.a[i];
return 0;
}
bool diff(rec a,rec b)
{
if(a.col!=b.col)return 1;
for(int i=1;i<5;i++)
if(a.a[i]!=b.a[i])return 1;
return 0;
}
int coun(rec a)
{
for(int i=1;i<5;i++)
if(a.a[i]==0x3f3f3f3f)return i-1;
return 4;
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&Map[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(!Map[i][j])continue;
if(Map[i][j]==Map[i-1][j])
{
gs[i][j][++sum[i][j]]=++gss;
gs[i-1][j][++sum[i-1][j]]=gss;
}
if(Map[i][j]==Map[i][j-1])
{
gs[i][j][++sum[i][j]]=++gss;
gs[i][j-1][++sum[i][j-1]]=gss;
}
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(!Map[i][j]&&!vis[i][j])
{gss++;dfs(i,j);}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(Map[i][j])
{
if(sum[i][j]>=1)
for(int k=1;k<=sum[i][j];k++)
{
e[++top].col=Map[i][j];
e[top].a[1]=gs[i][j][k];
e[top].a[2]=0x3f3f3f3f;
e[top].a[3]=0x3f3f3f3f;
e[top].a[4]=0x3f3f3f3f;
}
if(sum[i][j]>=2)
for(int k=1;k<=sum[i][j];k++)
for(int l=k+1;l<=sum[i][j];l++)
{
e[++top].col=Map[i][j];
e[top].a[1]=gs[i][j][k];
e[top].a[2]=gs[i][j][l];
e[top].a[3]=0x3f3f3f3f;
e[top].a[4]=0x3f3f3f3f;
}
if(sum[i][j]>=3)
for(int k=1;k<=sum[i][j];k++)
for(int l=k+1;l<=sum[i][j];l++)
for(int o=l+1;o<=sum[i][j];o++)
{
e[++top].col=Map[i][j];
e[top].a[1]=gs[i][j][k];
e[top].a[2]=gs[i][j][l];
e[top].a[3]=gs[i][j][o];
e[top].a[4]=0x3f3f3f3f;
}
if(sum[i][j]>=4)
{
e[++top].col=Map[i][j];
e[top].a[1]=gs[i][j][1];
e[top].a[2]=gs[i][j][2];
e[top].a[3]=gs[i][j][3];
e[top].a[4]=gs[i][j][4];
}
}
sort(e+1,e+top+1,cmp);
for(int i=1;i<=top;i++)
if(diff(e[i+1],e[i]))
{
if(coun(e[i])&1)ans+=now*(now-1)/2;
else ans-=now*(now-1)/2;
now=1;
}
else now++;
printf("%lld\n",ans);
return 0;
}
rp++
[CSP-S模拟测试]:连连看(图论+容斥)的更多相关文章
- [CSP-S模拟测试]:阴阳(容斥+计数+递推)
		
题目传送门(内部题16) 输入格式 第一行两个整数$n$和$m$,代表网格的大小.接下来$n$行每行一个长度为$m$的字符串,每个字符若为$W$代表这个格子必须为阳,若为$B$代表必须为阴,若为$?$ ...
 - [CSP-S模拟测试]:多维网格(组合数学+容斥)
		
题目传送门(内部题138) 输入格式 输入数据第一行为两个整数$d,n$. 第二行$d$个非负整数$a_1,a_2,...,a_d$. 接下来$n$行,每行$d$个整数,表示一个坏点的坐标.数 ...
 - [CSP-S模拟测试]:建设城市(city)(组合数学+容斥)
		
题目传送门(内部题8) 输入格式 一行三个整数$n,m,k$. 输出格式 一行一个整数表示答案.对$998244353$取模. 样例 样例输入 3 7 3 样例输出 数据范围与提示 对于10%的数据, ...
 - [CSP-S模拟测试]:Lighthouse(哈密顿回路+容斥)
		
题目背景 $Billions\ of\ lighthouses...stuck\ at\ the\ far\ end\ of\ the\ sky.$ 题目描述 平面有$n$个灯塔,初始时两两之间可以相 ...
 - csp-s模拟测试59(10.4)「Reverse」(set)·「Silhouette」(容斥)
		
A. Reverse 菜鸡wwb又不会了..... 可以线段树优化建边,然而不会所以只能set水了 发现对于k和当前反转点固定的节点x确定奇偶性所到达的节点奇偶性是一定的 那么set维护奇偶点,然后每 ...
 - 【GDOI2016模拟3.16】幂(容斥 + 模型复杂转化)
		
[GDOI2016模拟3.16]幂 \(X\in[1,A],Y\in[1,B]\),问:\(x^y\)的不用取值个数. \(A,B\)都是\(10^9\)级别. 然后我们开搞. 首先,假设一个合法的\ ...
 - hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥
		
Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Pr ...
 - 2018.10.30 NOIP模拟 字胡串(单调栈+容斥)
		
传送门 对于每个点,用单调栈求出它左右第一个比他大的位置. 然后对每个点O(logai)O(log_{a_i})O(logai)求出第一个拥有跟它不同二进制位的位置. 然后容斥一下就行了. 代码
 - NOIp模拟赛 巨神兵(状压DP 容斥)
		
\(Description\) 给定\(n\)个点\(m\)条边的有向图,求有多少个边集的子集,构成的图没有环. \(n\leq17\). \(Solution\) 问题也等价于,用不同的边集构造DA ...
 
随机推荐
- python 并发编程 多进程 JoinableQueue
			
JoinableQueue和Queue 使用一样 这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理.通知进程是使用共享的信号和条件变量来实现的. JoinableQueu ...
 - [转帖]Oracle 查询各表空间使用情况--完善篇
			
Oracle 查询各表空间使用情况--完善篇 链接:http://blog.itpub.net/28602568/viewspace-1770577/ 标题: Oracle 查询各表空间使用情况--完 ...
 - Linux命令学习(0)
			
作为一名前端,可能接触到linux的机会并不多,但这不代表就不需要学.对我而言,学习linux主要是为了方便部署我的项目到服务器,我并没有花时间去学这些,只是上网查怎么部署项目,然后按教程一步一步来, ...
 - NOIP赛前集训备忘录(含每日总结)(日更?。。。)
			
NOIP赛前集训备忘录(含每日考试总结) 标签: 有用的东西~(≧▽≦)/~啦啦啦 阅读体验:https://zybuluo.com/Junlier/note/1279194 考试每日总结(这个东西是 ...
 - PythonDay06
			
第六章 今日内容 小数据池 深浅拷贝 集合 小数据池 == is id == 判断两个值是否相等 is --- 是 判断两个值的内存地址是否相等 代码块:一个py文件,一个函数,一个模块,终端中每一行 ...
 - object in javascript
			
枚举对象属性 for....in 列举obj的可枚举属性,包括自身和原型链上的 object.keys() 只列举对象本身的可枚举属性 创建对象的几种方式 对象字面量 const pre='test' ...
 - [零基础学python]啰嗦的除法
			
除法啰嗦的,不仅是python. 整数除以整数 看官请在启动idle之后.练习以下的运算: >>> 2/5 0 >>> 2.0/5 0.4 >>> ...
 - 剑指offer-旋转数组的最小数字-数组-python
			
题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转 ...
 - datatable和dataset的区别
			
DataSet 是离线的数据源 DataTable 是数据源中的表.当然也可以自己建一张虚表.插入数据库中 DataSet是DataTable的容器DataSet可以比作一个内存中的数据库,DataT ...
 - 利用webSocket实现浏览器中多个标签页之间的通信
			
webSoket用来实现双向通信,客户端和服务端实时通信. webSoket优点和缺点? 优点:对于前端来说,使用简单,功能灵活,如果部署了webSocket服务器,可以实现实时通信. 缺点:需要服务 ...