[BZOJ2669] [cqoi2012]局部极小值

Description

有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次。如果一个格子比所有相邻格子(相邻是指有公共边或公共顶点)都小,我们说这个格子是局部极小值。给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

Input

输入第一行包含两个整数n和m(1<=n<=4, 1<=m<=7),即行数和列数。以下n行每行m个字符,其中“X”表示局部极小值,“.”表示非局部极小值。

Output

输出仅一行,为可能的矩阵总数除以12345678的余数。

Sample Input

3 2

X.

..

.X

Sample Output

60

试题分析

数据范围那么小,由于两个局部极小值在八连通中挨着的时候,是没有合法情况的,所以局部极小值不会超过8个。

这里要满足局部极小值集合严格为\(S\)的方案,这个严格看起来非常恶心,阻碍了我们的dp。

那么就尝试利用容斥把这个严格去掉,枚举集合\(F\)使得\(S\in F\)。

这个枚举\(F\)的集合是\(2^8\)的。 我们按照从小到大填入局部极小值,一个状态不合法当且仅当一个不是局部极小值的位置填了而它八连通中的局部极小值没有填。

所以\(f_{i,j}\)为填到第\(i\)个数字,其中集合\(j\)的局部极小值已经填完。

由状态可以得到转移方程:

$ f_{i,j}=\sum_{j\in k} f_{i-1,j-{ k} }+f_{i-1,j}\times (g_j-(i-1)) \(
其中\)g_j$表示去掉j的补集(还没有填的局部极小值)后还剩多少个格子。

然后容斥即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm> using namespace std;
#define LL long long inline LL read(){
LL x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const LL INF = 2147483600;
const LL MAXN = 100010;
const LL Mod = 12345678; LL dis[10][2]={{0,1},{1,0},{0,-1},{-1,0},{-1,-1},{1,1},{-1,1},{1,-1},{0,0}};
LL N,M; char str[11]; LL x[MAXN+1],y[MAXN+1];
LL vis[11][11],nod[11][11]; LL ans; inline void setting(LL x,LL y,LL g){
for(LL k=0;k<9;k++){
LL xx=x+dis[k][0],yy=y+dis[k][1];
if(xx<1||yy<1||xx>N||yy>M) continue;
vis[xx][yy]+=g;
} return ;
}
LL ret=0;
inline void setting2(LL x,LL y,LL g){
for(LL k=0;k<9;k++){
LL xx=x+dis[k][0],yy=y+dis[k][1];
if(xx<1||yy<1||xx>N||yy>M) continue;
if(g==1) {if(!nod[xx][yy]) nod[xx][yy]=1,--ret;}
else nod[xx][yy]=0;
} return ;
}
LL g[(1<<9)]; LL cnt;
inline void Pre(){
for(LL i=0;i<(1<<cnt);i++){
ret=N*M;
for(LL j=1;j<=cnt;j++)
if((i>>(j-1))&1) setting2(x[j],y[j],1);
g[(1<<cnt)-1-i]=ret;
for(LL j=1;j<=cnt;j++)
if((i>>(j-1))&1) setting2(x[j],y[j],-1);
} return ;
}
LL f[7*7][(1<<9)];
inline void dp(LL x){
f[0][0]=1;
for(LL i=1;i<=N*M;i++){
for(LL j=0;j<(1<<cnt);j++){
f[i][j]=0; //cout<<i<<endl;
if(g[j]<=(i-1)) continue; //cout<<"t:"<<g[j]<<" "<<j<<" "<<i-1<<endl;
if(j) for(LL k=1;k<=cnt;k++)
if((j>>(k-1))&1) f[i][j]+=f[i-1][j^(1<<(k-1))],f[i][j]%=Mod;
f[i][j]+=f[i-1][j]*((g[j]-(i-1))%Mod+Mod)%Mod; f[i][j]%=Mod;
}
} ans+=x*f[N*M][(1<<cnt)-1]%Mod; //cout<<f[N*M][(1<<cnt)-1]<<endl;
ans=(ans%Mod+Mod)%Mod; return ;
}
bool tt[17][17];
inline void dfs(LL stp,LL flag,LL line,LL row){
if(!stp){
Pre(); dp(flag); return ;
}
for(LL i=line;i<=N;i++){
for(LL j=(i==line?row:1);j<=M;j++){
if(!vis[i][j]){
setting(i,j,1); x[++cnt]=i,y[cnt]=j;
dfs(stp-1,flag,i+(j+1>M?1:0),(j+1>M?1:j+1));
setting(i,j,-1); --cnt;
}
}
} return ;
} int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
N=read(),M=read();
for(LL i=1;i<=N;i++){
scanf("%s",str+1);
for(LL j=1;j<=M;j++){
if(str[j]=='X') {
x[++cnt]=i,y[cnt]=j;
setting(i,j,1);
}
}
}
for(LL stp=0;stp<=8-cnt;stp++){
dfs(stp,(stp&1)?-1:1,1,1);
} printf("%lld\n",ans%Mod);
return 0;
}

[BZOJ2669] [cqoi2012]局部极小值的更多相关文章

  1. bzoj2669[cqoi2012]局部极小值 容斥+状压dp

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 774  Solved: 411[Submit][Status ...

  2. BZOJ2669 [cqoi2012]局部极小值 状压DP 容斥原理

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2669 题意概括 有一个n行m列的整数矩阵,其中1到nm之间的每个整数恰好出现一次.如果一个格子比所 ...

  3. [BZOJ2669][CQOI2012]局部极小值:DP+容斥原理

    分析 题目要求有且只有一些位置是局部极小值.有的限制很好处理,但是只有嘛,嗯...... 考虑子集反演(话说这个其实已经算是超集反演了吧还叫子集反演是不是有点不太合适),枚举题目给出位置集合的所有超集 ...

  4. bzoj2669 [cqoi2012]局部极小值 状压DP+容斥

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=2669 题解 可以发现一个 \(4\times 7\) 的矩阵中,有局部最小值的点最多有 \(2 ...

  5. 【BZOJ-2669】局部极小值 状压DP + 容斥原理

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 561  Solved: 293[Submit][Status ...

  6. bzoj 2669 [cqoi2012]局部极小值 DP+容斥

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 838  Solved: 444[Submit][Status ...

  7. 【BZOJ 2669】 2669: [cqoi2012]局部极小值 (状压DP+容斥原理)

    2669: [cqoi2012]局部极小值 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 667  Solved: 350 Description 有一 ...

  8. P3160 [CQOI2012]局部极小值

    题目 P3160 [CQOI2012]局部极小值 一眼就是状压,接下来就不知道了\(qwq\) 做法 我们能手玩出局部小值最多差不多是\(8,9\)个的样子,\(dp_{i,j}\)为填满\(1~i\ ...

  9. P3160 [CQOI2012]局部极小值 题解(状压DP+容斥)

    题目链接 P3160 [CQOI2012]局部极小值 双倍经验,双倍快乐 解题思路 存下来每个坑(极小值点)的位置,以这个序号进行状态压缩. 显然,\(4*7\)的数据范围让极小值点在8个以内(以下示 ...

随机推荐

  1. oracle04--伪列

    1. 伪列 1.1. 什么是伪列 伪列是在ORACLE中的一个虚拟的列. 伪列的数据是由ORACLE进行维护和管理的,用户不能对这个列修改,只能查看. 所有的伪列要得到值必须要显式的指定. 最常用的两 ...

  2. μC/OS-Ⅱ在C8051F060上的移植及其应用

    嵌入式操作系统是嵌入式应用的基础和核心.随着应用系统的不断复杂化和系统实时性需求的不断提高,对相应软件的逻辑结构.稳定性.实时性也提出了更高的要求,以传统的前后台编程模式编制软件将更加困难,而且容易出 ...

  3. 【codeforces】【比赛题解】#915 Educational CF Round 36

    虽然最近打了很多场CF,也涨了很多分,但是好久没写CF的题解了. 前几次刚刚紫名的CF,太伤感情了,一下子就掉下来了,不懂你们Div.1. 珂学的那场我只做了第一题……悲伤. 这次的Education ...

  4. USB descriptor【转】

    struct usb_device_descriptor { __u8 bLength;//设备描述符的字节数大小,为0x12 __u8 bDescriptorType;//描述符类型编号,为0x01 ...

  5. linux kernel的中断子系统之(三):IRQ number和中断描述符【转】

    转自:http://www.wowotech.net/linux_kenrel/interrupt_descriptor.html 一.前言 本文主要围绕IRQ number和中断描述符(interr ...

  6. Java 容器的打印

    Java容器类库中的两种主要类型,它们的区别在于容器中每个"槽"保存的元素个数 Clollection容器只能在保存一个元素,此类容器包括: List,它以特定顺序保存一组元素 S ...

  7. 用命令对sql进行备份

    利用T-SQL语句,实现数据库的备份与还原的功能 体现了SQL Server中的四个知识点: 1. 获取SQL Server服务器上的默认目录 2. 备份SQL语句的使用 3. 恢复SQL语句的使用, ...

  8. Kylin使用笔记-1: 安装

    2016年1月14日 9:57:23 星期四 背景介绍     Apache Kylin是一个开源的分布式分析引擎,提供Hadoop之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最 ...

  9. 【BZOJ】1566: [NOI2009]管道取珠

    题解 假如我们非常熟练的看出来,平方和转有序对统计的套路的话,应该就不难了 我们只需要统计(wayA,wayB)生成的序列一样的有序对个数就行 可以用一个\(n^3\)的dp解决 \(dp[i][j] ...

  10. HDU - 4458 计算几何判断点是否在多边形内

    思路:将飞机看成不动的,然后枚举时间看点是否在多边形内部. #include<bits/stdc++.h> #define LL long long #define fi first #d ...