1. 程式人生 > >bzoj 2331: [SCOI2011]地板【插頭dp】

bzoj 2331: [SCOI2011]地板【插頭dp】

一開始設計了四種狀態,多了一種已經拐彎但是長度為0的情況,後來發現不用,設012表示沒插頭,沒拐彎的插頭,拐了彎的插頭,然後轉移的話12,21,22都不合法,剩下的轉移腦補一下即可,ans只能在11,02,20取,別的都不是合法結束狀態

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=105,mod=20110520,has=739391;
int n,m,a[N][N],b[N],h[1000005],c[2],nw,la,tx,ty,ans;
char s[N];
struct qwe
{
    int ne,to[2],va[2];
}f[1000005];
void jia(int &x,int y)
{
    x+=y;
    x>=mod?x-=mod:0;
}
void add(int x,int v)
{
    int u=x%has+1;
    for(int i=h[u];i;i=f[i].ne)
        if(f[i].to[nw]==x)
        {
            jia(f[i].va[nw],v);
            return;
        }
    c[nw]++;
    f[c[nw]].ne=h[u];
    f[c[nw]].to[nw]=x;
    f[c[nw]].va[nw]=v;
    h[u]=c[nw];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
            if(s[j]=='_')
            {
                if(n>m)
                    a[i][j]=1;
                else
                    a[j][i]=1;
            }
    }
    if(n<m)
        swap(n,m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(a[i][j])
                tx=i,ty=j;
    b[0]=1;
    for(int i=1;i<=20;i++)
        b[i]=(b[i-1]<<2);
    c[0]=1,f[1].va[0]=1,f[1].to[0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=c[nw];j++)
            f[j].to[nw]<<=2;
        for(int j=1;j<=m;j++)
        {
            memset(h,0,sizeof(h));
            la=nw,nw^=1;
            c[nw]=0;
            for(int k=1;k<=c[la];k++)
            {
                int x=f[k].to[la],b1=(x>>(j*2-2))%4,b2=(x>>(j*2))%4,v=f[k].va[la];
                if(!a[i][j])
                {
                    if(b1==0&&b2==0)
                        add(x,v);
                }
                else if(b1==0&&b2==0)
                {
                    if(a[i+1][j]&&a[i][j+1])
                        add(x+2*b[j-1]+2*b[j],v);
                    if(a[i+1][j])
                        add(x+b[j-1],v);
                    if(a[i][j+1])
                        add(x+b[j],v);
                }
                else if(b1==0&&b2==1)
                {
                    if(a[i][j+1])
                        add(x+b[j],v);
                    if(a[i+1][j])
                        add(x+b[j-1]-b[j],v);
                }
                else if(b1==0&&b2==2)
                {
                    if(i==tx&&j==ty)
                        jia(ans,v);
                    add(x-2*b[j],v);
                    if(a[i+1][j])
                        add(x+2*b[j-1]-2*b[j],v);
                }
                else if(b1==1&&b2==0)
                {
                    if(a[i+1][j])
                        add(x+b[j-1],v);
                    if(a[i][j+1])
                        add(x-b[j-1]+b[j],v);
                }
                else if(b1==1&&b2==1)
                {
                    if(i==tx&&j==ty)
                        jia(ans,v);
                    add(x-b[j-1]-b[j],v);
                }
                else if(b1==2&&b2==0)
                {
                    if(i==tx&&j==ty)
                        jia(ans,v);
                    add(x-2*b[j-1],v);
                    if(a[i][j+1])
                        add(x-2*b[j-1]+2*b[j],v);
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}