来学插头DP了= =
GDKOI前觉得不会考数位DP,GDOI前觉得插头DP用不上。。
结果令人伤感>_<
这题并不用增加状态。。
只要在形成环的时候,让形成环的位置在最后一个必走点之后,并且此时只有一个联通分量。
因为必走点处肯定有插头。。所以只有一个联通分量就意味着所有必走点都连在一起了。
选择经过的点就在转移的时候多一种方法。。。
学的是最小表示法。。又长又慢TAT。。跳错坑了= =
#include<cstdio>
#include<iostream>
#include<cstring>
#define ull unsigned long long
using namespace std;
const int modd=,maxzt=;
struct zs{
struct hash{
ull too;int pre;
}e[maxzt];int tot,last[modd];
ull f[maxzt],zt[maxzt]; inline int get(ull v){
int i,x=v%modd;
for(i=last[x];i&&e[i].too!=v;i=e[i].pre);
if(i&&e[i].too==v)return i;
e[++tot].too=v,e[tot].pre=last[x],last[x]=tot;
zt[tot]=v;f[tot]=;
return tot;
}
}hm[];
int i,j,k,n,m,tx,ty;
int can[][];
ull ans;
char s[];
int v[]; inline void clr(bool now){
memset(hm[now].last,,modd<<),
hm[now].tot=;
} bool u[];int id[],mp[];
inline ull encode(){
memset(u,,);
ull x=;int tt=;
for(int i=;i<=m;mp[i]=id[mp[i]],x=x<<|mp[i],i++)
if(mp[i]&&!u[mp[i]])u[mp[i]]=,id[mp[i]]=++tt;
return x;
}
inline void decode(ull x){
for(int i=m;i>=;i--)mp[i]=x&,x>>=;
}
inline void shift(){
for(int i=m;i;i--)mp[i]=mp[i-];
mp[]=;
} inline void dp_blank(int x,int y,bool pre){
int i,left,up,j;bool now=pre^;ull zt,f;
clr(now);
for(i=;i<=hm[pre].tot;i++){
zt=hm[pre].zt[i],f=hm[pre].f[i],
decode(zt);
left=mp[y-],up=mp[y];
if(!left&&!up){
if(can[x+][y]&&can[x][y+]){
mp[y-]=mp[y]=;
if(y==m)shift();
hm[now].f[ hm[now].get(encode()) ]+=f;
}
if(can[x][y]==){
mp[y-]=mp[y]=;
if(y==m)shift();
hm[now].f[ hm[now].get(encode()) ]+=f;
}
}
if((!left)^(!up)){
j=left|up;
if(can[x+][y]){
mp[y-]=j,mp[y]=;
if(y==m)shift();
hm[now].f[ hm[now].get(encode()) ]+=f;
}
if(can[x][y+]){
mp[y-]=,mp[y]=j;
if(y==m)shift();
hm[now].f[ hm[now].get(encode()) ]+=f;
}
}
if(left&&up){
if(left==up)
if(x>tx||(x==tx&&y>=ty)){
mp[y-]=mp[y]=;
if(encode()==)ans+=f;
}else;
else{
mp[y-]=mp[y]=;
for(j=;j<=m;j++)if(mp[j]==up)mp[j]=left;
if(y==m)shift();
hm[now].f[ hm[now].get(encode()) ]+=f;
}
}
}
}
inline void dp_bar(int x,int y,bool pre){
int i,left,up;bool now=pre^;ull f,zt;
clr(now);
for(i=;i<=hm[pre].tot;i++){
zt=hm[pre].zt[i],f=hm[pre].f[i];
decode(zt);
left=mp[y-],up=mp[y];
if(!left&&!up){
if(y==m)shift();
hm[now].f[ hm[now].get(encode()) ]+=f;
}
}
} int main(){
int TT;
scanf("%d",&TT);v['X']=,v['O']=,v['*']=;
for(int TTT=;TTT<=TT;TTT++){
scanf("%d%d",&n,&m);
memset(can,,sizeof(can));
for(i=;i<=n;i++)
for(scanf("%s",s+),j=;j<=m;j++){
can[i][j]=v[s[j]];
if(s[j]=='O')tx=i,ty=j;
} for(i=n,j=;i;i--){
for(j=m;j;j--)if(can[i][j]==)break;
if(j>)break;
}
tx=i,ty=j; bool now=,pre=;ans=;
clr(),hm[pre].f[ hm[pre].get() ]=;
for(i=;i<=n;i++)for(j=;j<=m;j++,swap(now,pre))
if(can[i][j])dp_blank(i,j,pre);else dp_bar(i,j,pre);
printf("Case %d: %I64u\n",TTT,ans);
}
return ;
}