TopCoder SRM 616 DIV1 ThreeLLogo(TopCoder - 13059 )

题面

题意

给出一个矩阵,矩阵中的点是白点或黑点,现在要你放入3个’L’形,要求‘L’形都不经过黑点,问一共有几种方案。

做法

首先暴力枚举这三个‘L’左下角的点在哪一行,然后一列一列更新状态,对于每个L有三种状态:
0:表示还未放。
1:表示正在放(L横着的这段)。
2:已经放好了。
然后用dp[列数][状态(3*3*3)]。
需要注意的是,L横着的这段至少有两个,因此在更新的时候要特判一下,还有在从0->1时,需要乘上竖着的‘L’放的种类数,这个数量与地图和另外两个’L’的状态都有关系,以及几个‘L’在同一行时的情况。
此题状态转移时,特判比较多,详见代码。

代码

#include <bits/stdc++.h>
#define ll long long
#define N 35
using namespace std;

class ThreeLLogo
{
    public:
        long long countWays( vector <string> grid );
};

ll up[N][N],pos[5],ans,dp[N][30],a,b,c,na,nb,nc,res,tmp;
bool mm[N][N];

inline void get(ll u)
{
    a=u/9;
    b=u%9/3;
    c=u%3;
}

inline ll fget(ll u,ll v,ll w)
{
    return u*9+v*3+w;
}

//0 未放
//1 在放
//2 放完 

long long ThreeLLogo::countWays(vector <string> grid)
{
    ll i,j,k,m=grid.size(),n=grid[0].size();
    memset(mm,0,sizeof(mm));
    memset(up,0,sizeof(up));
    ans=0;
    for(i=0; i<m; i++)
    {
        for(j=0; j<n; j++)
        {
            if(grid[i][j]=='#')
            {
                mm[i+1][j+1]=1;
                up[i+1][j+1]=-1;
            }
            else if(!i) up[i+1][j+1]=0;
            else up[i+1][j+1]=up[i][j+1]+1;
        }
    }
    for(i=1;i<=m+1;i++) mm[i][n+1]=1;
    for(i=1;i<=n;i++) mm[m+1][i]=1;
    for(pos[1]=1;pos[1]<=m;pos[1]++)
    {
        for(pos[2]=pos[1];pos[2]<=m;pos[2]++)
        {
            for(pos[3]=pos[2];pos[3]<=m;pos[3]++)
            {
                memset(dp,0,sizeof(dp));
                dp[0][0]=1;
                for(i=0;i<n;i++)
                {
                    for(j=0;j<27;j++)
                    {
                        if(!dp[i][j]) continue;
                        get(j);
                        for(k=0;k<8;k++)
                        {
                            na=a+k/4;
                            nb=b+k/2%2;
                            nc=c+k%2;
                            if(na>2||nb>2||nc>2) continue;
                            if((na==1 || a==1) && mm[pos[1]][i+1]) continue;
                            if((nb==1 || b==1) && mm[pos[2]][i+1]) continue;
                            if((nc==1 || c==1) && mm[pos[3]][i+1]) continue;
                            if(!a && na==1 && mm[pos[1]][i+2]) continue;
                            if(!b && nb==1 && mm[pos[2]][i+2]) continue;
                            if(!c && nc==1 && mm[pos[3]][i+2]) continue;
                            if(pos[1]==pos[2] && na<nb) continue;
                            if(pos[2]==pos[3] && nb<nc) continue;
                            res=1;
                            if(!a && na==1) res*=up[pos[1]][i+1];
                            if(!b && nb==1)
                            {
                                if(na==1 || a==1) res*=min(up[pos[2]][i+1],pos[2]-pos[1]-1);
                                else res*=up[pos[2]][i+1];
                            }
                            res=max(res,0ll);
                            if(!c && nc==1)
                            {
                                tmp=up[pos[3]][i+1];
                                if(na==1 || a==1) tmp=min(tmp,pos[3]-pos[1]-1);
                                if(nb==1 || b==1) tmp=min(tmp,pos[3]-pos[2]-1);
                                res*=tmp;
                            }
                            res=max(res,0ll);
                            dp[i+1][fget(na,nb,nc)]+=dp[i][j]*res;
                        }
                    }
                }
                ans+=dp[n][26];
            }
        }
    }
    return ans;
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/81001006