LA 4058 ACM Puzzles dp(插头)

题意:给出3*n(n<=2000)的棋盘,有22种相连的方块(不能旋转),问有多少种方法填满这个棋盘(要求取模)






#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;

#define all(x) (x).begin(), (x).end()
#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)
#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)
#define ysk(x)  (1<<(x))
#define RI(s)  ((s&(56))>>3)
#define LE(s)  (s&(7))
typedef long long ll;
typedef pair<int, int> pii;
const int INF =0x3f3f3f3f;
const int maxn=2000    ;
int maxS,n;
const ll mod=1000000000000;
ll dp[maxn+2][64];
inline bool exists_right(int s)
{
    return  (s&ysk(3))|| (s&ysk(4)) || (s&ysk(5) );
}
int A;
struct Piece
{
    int add,le,ri;
    Piece(){}
    Piece(int le,int ri):le(le),ri(ri){

        add= RI(le)?2:1;
    }
    void show()//用于debug()
    {
        int s;
        if(RI(ri))  s= (ri<<3) |le;
        else
        {
            s= (ri<<6) ;
            if(RI(le)) s|=le;
            else  s|= (le<<3);

        }

        printf("%dth block:\n",A++);
        for(int i=0;i<3;i++)
        {
            for(int st=i;st<9;st+=3)
            {
                putchar(' ');
                if(ysk(st)&s)  printf("1");
                else  printf("0");
            }
            putchar('\n');
        }
        printf("add=%d\n",add);
        putchar('\n');

    }

}a[22];


int make(int a=0,int b=0,int c=0,int d=0,int e=0,int f=0 )
{
    int t=0;
    t=a*ysk(0)+b*ysk(1)+c*ysk(2)+d*ysk(3)+e*ysk(4)+f*ysk(5);
    return t;

}
void pre()
{
    maxS=0;
    for0(i,6) maxS|=ysk(i);
   a[0]=Piece(make(1,1,1),make(0));
   a[1]=Piece(make(1,1,1),make(0,1,0));
   a[2]=Piece(make(1,0,1,1,1,1),make(0));
   a[3]=Piece(make(0,1,1,1,1,1),make(0));
   a[4]=Piece(make(0,1,0,1,1,1),make(0,1,0));
   a[5]=Piece(make(1,1,1),make(1,0,1));
   a[6]=Piece(make(0,1,0,1,1,1),make(0));
   a[7]=Piece(make(0,0,1,0,1,1),make(1,1,0));
   a[8]=Piece(make(1,0,0,1,1,0),make(0,1,1));
   a[9]=Piece(make(0,1,1),make(1,1,0));
   a[10]=Piece(make(1,1,0),make(0,1,1));
   a[11]=Piece(make(1,1,1),make(1,1,0));
   a[12]=Piece(make(1,1,0,1,1,1),make(0));
   a[13]=Piece(make(1,1,1),make(1,0,0));
   a[14]=Piece(make(1,0,0,1,1,1),make(0));
   a[15]=Piece(make(0,1,1),make(1,1,0,1,0,0));
   a[16]=Piece(make(1,1,0),make(0,1,1,0,0,1));
   a[17]=Piece(make(1,1,1),make(0,0,1));
   a[18]=Piece(make(0,0,1,1,1,1),make(0));
   a[19]=Piece(make(1,0,0,1,1,1),make(1,0,0));
   a[20]=Piece(make(0,0,1,1,1,1),make(0,0,1));
   a[21]=Piece(make(1,1,1),make(0,1,1));


}


bool join(int s1,int s2)
{
    if(!RI(s1)){//s1右边只露出一列
         return ( !(LE(s1)&LE(s2))  )&& ( (LE(s1)| LE(s2)) ==7)&& (!RI(s2)||RI(s2)==7   );
    }
    else {
         return  (  !(s1&s2) ) && ( (s1|s2) ==maxS);
    }
}
ll DP(int cols,int s)
{
    if(cols==maxn)
    {
        if(!s)  return 1;
        return 0;
    }
    if(~dp[cols][s])  return dp[cols][s];
    ll & ans=dp[cols][s];
    ans=0;
    for0(i,22)
    {
        int add=a[i].add;
        if(cols+add>maxn)  continue;
        int s2=a[i].le;
        int s3=a[i].ri;
        if(join(s,s2))  ans=(ans+DP(cols+add,s3))%mod;
    }
    return ans;

}



void debug()
{
    for0(i,22)
    {
        a[i].show();
    }
}

int main()
{
    pre();
    int kase=0;
    memset(dp,-1,sizeof dp);
    while(~scanf("%d",&n)&&n)//n列时,可以认为是[maxn-n+1,n]这部分。
    {
        int t=maxn-n;
        printf("Case %d: %lld\n",++kase,DP(t,0));
    }

   return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值