解题思路:

分类讨论即可。

代码(懒得删Debug了):

 #include<map>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#define black '#'
#define white 'o'
#define BLACK_AND_WHITE int main(){/*freopen("a.in","r",stdin);*/scanf("%d",&T);while(T--)Black_and_White();return 0;}
typedef long long lnt;
typedef unsigned int uit;
typedef unsigned long long unt;
int T;
int n,m;
int p,q;
unt ans=;
int mp[][];
char cmd[];
uit code[];
uit tod[];
int clor[];
bool col[];
std::map<unt,unt>dp[],ooo;
void minpress(uit *cd)
{
int cnt=;
memset(clor,,sizeof(clor));
for(int i=;i<=m;i++)
{
if(!clor[cd[i]])
clor[cd[i]]=++cnt;
cd[i]=clor[cd[i]];
}
return ;
}
unt compress(uit *cd,int hc)
{
unt ret=hc;
minpress(cd);
for(int i=;i<=m;i++)
ret=ret*10ull+cd[i];
return ret;
}
void decompress(uit *cd,bool *cl,unt sit)
{
for(int i=m;i>=;i--)
{
cd[i]=sit%10ull;
sit/=10ull;
}
cl[]=sit;
for(int i=;i<=m;i++)
if(cd[i]!=cd[i-])
cl[i]=-cl[i-];
else
cl[i]=cl[i-];
return ;
}
bool banned(int l,int r,int pos,uit *cd)
{
for(int i=;i<l;i++)
if(cd[i]==cd[pos-])
return false;
for(int i=r-;i<=m;i++)
if(cd[i]==cd[pos-])
return false;
return true;
}
void update(int cmd,unt tmp,unt v)
{
if(dp[cmd].find(tmp)==dp[cmd].end())
dp[cmd][tmp]=v;
else
dp[cmd][tmp]+=v;
return ;
}
void Insert(int ii,int jj,unt s,unt v,bool b)
{
decompress(code,col,s);
int lu,uu,ll,hc=col[];
/* printf("%d ",hc);
for(int k=0;k<=m;k++)
printf("%d ",code[k]);
printf("%d",v);
/* puts("");/*
for(int i=0;i<=m;i++)
printf("%d ",col[i]);*/
uu=col[jj]^b;
lu=col[jj-]^b;
ll=col[jj-]^b;
/* printf(uu?"b":"w");
printf(lu?"b":"w");
printf(ll?"b":"w");*/
// puts("");
uit maxs=;
for(int i=;i<=m;i++)
maxs=std::max(maxs,code[i]);
for(int i=;i<=m;i++)
tod[i]=code[i];
if(ll)
{
if(lu)
{
if(uu)
tod[jj-]=maxs+;
else
tod[jj-]=tod[jj];
}else{
if(uu)
{
if(ii==n&&jj==m)
return ;
if(banned(jj-,jj+,jj+,tod))
return ;
//printf("+1\n");
tod[jj-]=maxs+;
}else
tod[jj-]=tod[jj];
}
}else{
if(lu)
{
if(uu)
{
if(banned(jj-,jj+,jj+,tod))
{
if(ii!=n||(jj!=m&&jj!=m-))return ;
for(int i=;i<jj-;i++)
if(col[i]==col[jj])
return ;
for(int i=jj+;i<=m;i++)
if(col[i]==col[jj])
return ;
}
tod[jj-]=tod[jj-];
}else{
tod[jj]=tod[jj-]=tod[jj-];
for(int i=;i<=m;i++)
{
if(code[i]==code[jj]||code[i]==code[jj-])
tod[i]=tod[jj-];
}
}
}else{
if(uu)
{
if(banned(jj-,jj+,jj+,tod))
{
if(ii!=n||(jj!=m&&jj!=m-))return ;
for(int i=;i<jj-;i++)
if(col[i]==col[jj])
return ;
for(int i=jj+;i<=m;i++)
if(col[i]==col[jj])
return ;
}
tod[jj-]=tod[jj-];
}else return ;
}
}
unt tmp=compress(tod,hc);
if(ii==n&&jj==m)
{
int cnt=;
decompress(code,col,tmp);
memset(clor,,sizeof(clor));
for(int i=;i<=m;i++)
if(!clor[code[i]])
clor[code[i]]=++cnt;
if(cnt<=)
ans+=v;
return ;
}
update(p,tmp,v);
return ;
}
void Insert(int i,unt s,unt v,bool b)
{
decompress(code,col,s);
int uu,hc=col[];
/* printf("%d ",hc);
for(int k=0;k<=m;k++)
printf("%d ",code[k]);
printf("%d ",v);
puts("");*/
for(int i=;i<=m;i++)
tod[i]=code[i];
uu=col[]^b;
if(uu)
{
if(banned(,,,tod))
return ;
code[]=;
hc=b;
}else
code[]=code[];
unt tmp=compress(code,hc);
if(i==n&&m==)
{
int cnt=;
decompress(code,col,tmp);
memset(clor,,sizeof(clor));
for(int ii=;ii<=m;ii++)
if(!clor[code[ii]])
clor[code[ii]]=++cnt;
if(cnt<=)
ans+=v;
}
update(p,tmp,v);
return ;
}
unt move(unt x)
{
decompress(code,col,x);
int hc=col[];
for(int i=m;i;i--)
code[i]=code[i-];
return compress(code,hc);
}
void Move(void)
{
ooo.clear();
for(std::map<unt,unt>::iterator i=dp[p].begin();i!=dp[p].end();i++)
ooo[i->first]=i->second;
dp[p].clear();
for(std::map<unt,unt>::iterator i=ooo.begin();i!=ooo.end();i++)
{
update(p,move(i->first),i->second);
// printf("%I64u %I64u\n",move(i->first),i->second);
}
return ;
}
void Black_and_White(void)
{
dp[].clear();
dp[].clear();
ans=;
p=,q=;
memset(mp,,sizeof(mp));
memset(code,,sizeof(code));
memset(clor,,sizeof(clor));
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",cmd+);
for(int j=;j<=m;j++)
{
if(cmd[j]==white)
mp[i][j]=-;
else if(cmd[j]==black)
mp[i][j]=;
else
mp[i][j]=;
}
}
if(n==&&m==)
{
if(mp[][])
puts("");
else
puts("");
return ;
}
for(int i=;i<(<<m);i++)
{
int cnt=;
code[]=code[]=;
bool ban=false;
for(int j=;j<=m;j++)
{
if(mp[][j]==&&((i&(<<(j-)))==))ban=true;
if(mp[][j]==-&&(i&(<<(j-)))) ban=true;
if(ban)break;
}
if(ban)
continue;
for(int j=;j<=m;j++)
{
if((bool)(i&(<<(j-)))^(bool)(i&(<<(j-))))
cnt++;
code[j]=cnt;
}
int co=i&;
// printf("%d ",co);
// puts("");
unt s=compress(code,co);
// printf("%d\n",s);
update(p,s,);
}
for(int i=;i<=n;i++)
{
// puts("\n~~~~~~~~~~~~~~~~~~~~~~");
std::swap(p,q);
dp[p].clear();
for(std::map<unt,unt>::iterator k=dp[q].begin();k!=dp[q].end();k++)
{
unt s=k->first;
unt v=k->second;
if(mp[i][]!=)
Insert(i,s,v,);
if(mp[i][]!=-)
Insert(i,s,v,);
}
// puts("_________________________");
for(int j=;j<=m;j++)
{
// puts("\n~~~~~~~~~~~~~~~~~~~~~~");
std::swap(p,q);
dp[p].clear();
for(std::map<unt,unt>::iterator k=dp[q].begin();k!=dp[q].end();k++)
{
unt s=k->first;
unt v=k->second;
if(mp[i][j]!=)
Insert(i,j,s,v,);
if(mp[i][j]!=-)
Insert(i,j,s,v,);
}
// puts("_________________________");
}
// puts("%d");
Move();
}
printf("%llu\n",ans);
return ;
}BLACK_AND_WHITE

BZOJ3336: Uva10572 Black and White(插头Dp)的更多相关文章

  1. BZOJ 3336 Black and White (插头DP)

    题目大意: 给你一个n×m的网格,有一些格子已经被涂上了白色或者黑色,让你用黑色或白色填剩下的格子,且填好的网格必须保证: 1.对于任意2×2的子矩阵的4个格子,它们的颜色不能都相同 2.所有黑色的块 ...

  2. bzoj3336 Uva10572 Black and White

    题目描述: 数据范围:2<=n,m<=8 题解: 很明显需要状压.但是怎么压不知道,压什么不知道. 然后从条件下手. 条件1要求黑色在一起白色在一起,记录轮廓线很容易做到. 条件2要求不能 ...

  3. 插头dp练习

    最近学了插头dp,准备陆续更新插头dp类练习. 学习论文还是cdq那篇<基于连通性状态压缩的动态规划问题>. 基本的想法都讲得很通透了,接下来就靠自己yy了. 还有感谢kuangbin大大 ...

  4. 插头dp

    插头dp 感受: 我觉得重点是理解,算法并不是直接想出怎样由一种方案变成另一种方案.而是方案本来就在那里,我们只是枚举状态统计了答案. 看看cdq的讲义什么的,一开始可能觉得状态很多,但其实灰常简单 ...

  5. HDU 4113 Construct the Great Wall(插头dp)

    好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...

  6. HDU 4949 Light(插头dp、位运算)

    比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...

  7. 插头DP专题

    建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...

  8. HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)

    插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...

  9. HDU 1693 Eat the Trees(插头DP)

    题目链接 USACO 第6章,第一题是一个插头DP,无奈啊.从头看起,看了好久的陈丹琦的论文,表示木看懂... 大体知道思路之后,还是无法实现代码.. 此题是插头DP最最简单的一个,在一个n*m的棋盘 ...

随机推荐

  1. Rendering and compositing out of process iframes

    For Developers‎ > ‎Design Documents‎ > ‎Out-of-Process iframes (OOPIFs)‎ > ‎ Rendering and ...

  2. js实现简易打点计时器

    很简单的实现一个打点计时器,规定从start至end,每次加1,每次打印间隔100ms,并且返回取消方法. 代码如下: //打点计时器,每间隔100毫秒+1 function count(start, ...

  3. AWK的介绍学习

    第一节.awk的工作流程和基本用法 1.awk介绍 awk是一种报表生成器,就是对文件进行格式化处理的,这里的格式化不是文件系统的格式化,而是对文件内容进行各种"排版",进而格式化 ...

  4. Windows 10 计划带来颜文字和Sandbox

    在最新的 Window 10 测试版 Build 18305 中,Windows 10 增加了对颜文字(kaomoji)的支持. Kaomoji 是由日本符号序列组成的面脸部表情的名称.虽然有些人,比 ...

  5. conda常用命令,如何在conda环境中安装gym库?

    查看已安装的环境: conda info -e 或 conda env list 创建新环境gymlab: conda create -n gymlab python=3.5 激活环境gymlab: ...

  6. HNU 12933 Random Walks Catalan数 阶乘求逆元新技能

    一个Catalan数的题,打表对每个数都求一次逆元会T,于是问到了一种求阶乘逆元的打表新方法. 比如打一个1~n的阶乘的逆元的表,假如叫inv[n],可以先用费马小定理什么的求出inv[n],再用递推 ...

  7. 【SRM 716 DIV 1 A】 ConstructLCS

    Problem Statement A string S is a subsequence of a string T if we can obtain S from T by erasing som ...

  8. ubuntu中开启、关闭防火墙

    1.关闭ubuntu的防火墙        ufw disable 开启防火墙 ufw enable 2.卸载了iptables        apt-get remove iptables 3.关闭 ...

  9. 软件project总结

    软件project的文档完结了.在这里面学到了好多东西.也通过它分析了对机房收费系统进行了更加具体的分析.尽管早就明确了之间的联系,可是越温习越体会到逻辑的重要性和全心全意为人民服务的精神. 这些文档 ...

  10. 111.final与override

    #include <iostream> using namespace std; class myclass { public: //后面加一个final,则禁止虚函数被子类重写 //fi ...