2331: [SCOI2011]地板

插头Dp

/**************************************************************
    Problem: 2331
    User: sxb_201
    Language: C++
    Result: Accepted
    Time:980 ms
    Memory:43148 kb
****************************************************************/
 
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define MO 20110520
int ans[5000000];
int f[700000],top;
int n,m;
char s[200][200];
bool ok(int x)
{
    for(int i=0;i<=m+1;i++)
    {
        if( (x & (3<<(i*2)) )  ==(3<<(i*2))) return false;
    }
    return true;
}
int F(int x,int now,int up,int left)
{
    int tmp=(x>>(now*2))%4;
    tmp^=up;
    x^=( tmp<<(now*2) );
     
    x>>=2;
    x<<=2;
    x^=left;
     
    return x;
}
char a[200][200];
int g[5000000];
int main()
{
    cin >>n >>m;
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]+1);
    if(n>=m)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                a[i][j]=s[i][j];
    else
        {
            swap(n,m);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    a[i][j]=s[j][i];
        }
 
    for(int i=0;i< (1<<((m+1)*2));i++)
    {
        if(ok(i)) f[++top]=i;
    }
    ans[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        if(a[i][j]!='*')
        {
            for(int k=1;k<=top;k++)
                g[f[k]]=0; 
             
            for(int k=1;k<=top;k++)
            {
                int tmp=f[k];
                if(ans[tmp]==0) continue;
                int left=tmp%4;
                int up=  ( tmp>>( j*2) )%4;
                 
                int to; 
                if(up==0&&left==0)
                {
                    to=F(tmp,j,0,2);
                    g[to]=(g[to]+ans[tmp])%MO;
                    to=F(tmp,j,2,0);
                    g[to]=(g[to]+ans[tmp])%MO;
                    to=F(tmp,j,1,1);
                    g[to]=(g[to]+ans[tmp])%MO;
                }
                if(up==0&&left==1)
                {
                    to=F(tmp,j,0,0);
                    g[to]=(g[to]+ans[tmp])%MO;
                    to=F(tmp,j,0,1);
                    g[to]=(g[to]+ans[tmp])%MO;
                }
                if(up==0&&left==2)
                {
                    to=F(tmp,j,0,2);
                    g[to]=(g[to]+ans[tmp])%MO;
                    to=F(tmp,j,1,0);
                    g[to]=(g[to]+ans[tmp])%MO;
                }
                if(up==1&&left==0)
                {
                    to=F(tmp,j,0,0);
                    g[to]=(g[to]+ans[tmp])%MO;
                    to=F(tmp,j,1,0);
                    g[to]=(g[to]+ans[tmp])%MO;          
                }
                if(up==1&&left==1)
                {
                     
                }
                if(up==1&&left==2)
                {
                         
                }
                if(up==2&&left==0)
                {
                    to=F(tmp,j,0,1);
                    g[to]=(g[to]+ans[tmp])%MO;
                    to=F(tmp,j,2,0);
                    g[to]=(g[to]+ans[tmp])%MO;
                }
                if(up==2&&left==1)
                {
                     
                }
                if(up==2&&left==2)
                {
                    to=F(tmp,j,0,0);
                    g[to]=(g[to]+ans[tmp])%MO;
                }   
            }
        //  memset(ans,0,sizeof(ans));
            for(int k=1;k<=top;k++)
                ans[f[k]]=g[f[k]];
        }
        else
        {
            for(int k=1;k<=top;k++)
                if(f[k]%4!=0||((f[k]>>(j*2))%4!=0))
                    ans[f[k]]=0;
        }
         
        for(int k=1;k<=top;k++)
            if(f[k]%4!=0)
                ans[f[k]]=0;
    }
     
    cout<<ans[0]<<endl;
     
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值