题目

分析

其实原题就是【cqoi2012】【bzoj2669】局部极小值。

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

给出所有局部极小值的位置,你的任务是判断有多少个可能的矩阵。

发现,X的位置最多有8个,那我们考虑状压dp。

我们从小到大把数填进去,用\(f_{i,j}\)表示,把第i个数填进去后,每个X是否被填了数,用二进制数j表示。

预处理出\(rest_j\)表示填充状态为j时共有多少位置是可以填充的(包括已填充的局部极小值位置)

转移:

\[f_{i,j}=f_{i-1,j}*(rest_j-(i-1))+\sum_{k\in{j}}f_{i-1,j-2^{k-1}}
\]

但是有些不是为X的位置有可能也是局部极小值,那么我们用容斥,每次把一下有可能出现局部极小值的地方改为X,当额外增加的X的个数为奇数,ans就减去dp得所得的答案,否则ans加上dp得所得的答案。

其中dp方面这篇论文(第5页到第8页)讲的非常清楚

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=12345678;
const int N=10;
int z[9][2]=
{
{-1,-1},
{-1,0},
{-1,1},
{0,-1},
{0,1},
{1,-1},
{1,0},
{1,1},
{0,0}
};
int a[N][N],T,n,m,ans,f[N*N][2000],mi[10],sign[N][2],tot,rest[2000];
char c[N][N];
bool bz[N][N];
int val()
{
tot=0;
int state=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(c[i][j]=='X')
{
state+=mi[tot];
sign[++tot][0]=i;
sign[tot][1]=j;
}
}
for(int i=0;i<=state;i++)
{
memset(bz,true,sizeof(bz));
rest[i]=0;
for(int j=1;j<=tot;j++)
if((mi[j-1]&i)==0)
{
for(int k=0;k<=8;k++)
{
bz[sign[j][0]+z[k][0]][sign[j][1]+z[k][1]]=false;
}
}
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++)
{
if(bz[j][k])
rest[i]++;
}
}
f[0][0]=1;
for(int i=1;i<=n*m;i++)
for(int j=0;j<=state;j++)
{
f[i][j]=0;
(f[i][j]+=f[i-1][j]*(rest[j]-i+1)%mo)%=mo;
for(int k=1;k<=tot;k++)
{
if(mi[k-1]&j)
{
(f[i][j]+=f[i-1][j-mi[k-1]])%=mo;
}
}
}
return f[n*m][mi[tot]-1];
}
int dg(int x,int y,int z1)
{
if(x>n)
{
(ans+=(val()*(z1%2?1:-1))%mo)%mo;
return 0;
}
int xx=x,yy=y+1;
if(yy>m)
{
yy=1;
xx++;
}
dg(xx,yy,z1);
bool q=true;
for(int i=0;i<=8;i++)
{
if(c[x+z[i][0]][y+z[i][1]]=='X')
{
q=false;
break;
}
}
if(q)
{
c[x][y]='X';
dg(xx,yy,z1+1);
c[x][y]='.';
}
}
int main()
{
mi[0]=1;
for(int i=1;i<=9;i++)
mi[i]=mi[i-1]*2;
scanf("%d",&T);
while(T--)
{
tot=0;
ans=0;
memset(c,0,sizeof(c));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
c[i][j]=getchar();
while(c[i][j]!='X' && c[i][j]!='.')
c[i][j]=getchar();
if(c[i][j]=='.')
tot++;
}
}
if(tot==n*m)
{
printf("0\n");
continue;
}
for(int i=1;i<=n && ans!=-1;i++)
{
for(int j=1;j<=m;j++)
{
bool q=true;
if(c[i][j]=='X')
for(int k=0;k<=7;k++)
{
if(c[i+z[k][0]][j+z[k][1]]=='X')
{
q=false;
ans=-1;
break;
}
}
if(!q)
{
ans=-1;
break;
}
}
}
if(ans==-1)
{
printf("0\n");
}
if(ans!=-1)
{
dg(1,1,1);
printf("%d\n",(ans%mo+mo)%mo);
}
}
}

最新文章

  1. js 封装设计cookie
  2. WebUpLoder 能自动预览,能多实例,包括后台demo
  3. HTTP请求常见状态码
  4. transform实现的时钟效果
  5. MPlayer-ww 增加边看边剪切功能
  6. Microsoft Dynamics AX 2012 X++ Editor Extensions
  7. 安装ADT Cannot complete the install because one or more required items could not be found.
  8. Delphi模式设计
  9. asp.net中ScriptManager自带Ajax与jQuery事件冲突
  10. 【转】两种方法教你在Ubuntu下轻松关闭触摸板(TinkPad)
  11. server服务器信息页面添加步骤
  12. Keychain 浅析
  13. 简洁明了的插值音频重采样算法例子 (附完整C代码)
  14. Python的编码风格
  15. java语言编写矩阵的四则运算
  16. maven学习三
  17. android 活动的生命周期
  18. 设计模式 (二)——观察者模式(Observer,行为型)
  19. Android中EditText焦点问题
  20. oracle unix时间戳与date转换

热门文章

  1. Golang基础(5):Go语言反射规则
  2. IDEA 双击只选择了一个变量的某部分单词
  3. Java第六周实验+总结
  4. C语言作业7
  5. poj3191(负进位制)
  6. 【6.28校内test】T2 【音乐会】二重变革
  7. 【洛谷p1058】立体图(已完结)
  8. 解决 Intellij IDEA Cannot Resolve Symbol ‘BASE Decoder’ 问题
  9. Jquery复习(三)之链式调用
  10. qt使用QWT注意事项