题意:给出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;
}