瓷砖铺放 (状压DP+矩阵快速幂)

未加矩阵快速幂 50分

 1 const dx:array[1..8,1..3] of longint=
 2     ((-1,0,0),(-1,0,0),(1,0,0),(0,1,0),(-1,0,0),(-1,1,0),(0,1,0),(-1,0,1));
 3     dy:array[1..8,1..3] of longint=
 4     ((0,1,0),(0,-1,0),(0,-1,0),(1,0,0),(0,1,-1),(0,0,-1),(1,0,-1),(0,1,0));
 5     mo=65521;
 6 var n,m,lx,i,j,k:longint;
 7     a:array[0..10,0..10] of longint;
 8     g:array[0..5000,0..5000] of longint;
 9     dp:array[0..200,0..5000] of longint;
10 function ok(x,y:longint):boolean; inline;
11 begin
12     if (x>=1) and (x<=3) and (y>=1) and (y<=m) and (a[x,y]=0) then exit(true);
13     exit(false);
14 end;
15 function check(y,j:longint):boolean;
16 var i,x:longint;
17 begin
18     x:=2;
19     if not ok(x,y) then exit(false);
20     for i:=1 to 3 do
21         if not ok(x+dx[j,i],y+dy[j,i]) then exit(false);
22     exit(true);
23 end;
24 procedure fill(y,j,cl:longint);
25 var i,x:longint;
26 begin
27     x:=2;
28     a[x,y]:=cl;
29     for i:=1 to 3 do
30         a[x+dx[j,i],y+dy[j,i]]:=cl;
31 end;
32 procedure dfs(x,lt:longint);
33 var i,j,sum:longint;
34 begin
35     if x=m+1 then
36     begin
37         for i:=1 to m do if a[1,i]=0 then exit; //保证了DP的正确性
38         sum:=0;
39         for i:=2 to 3 do
40             for j:=1 to m do
41                 sum:=sum*2+a[i,j];
42         inc(g[lt][sum]);
43         exit;
44     end;
45     dfs(x+1,lt);
46     for i:=1 to 8 do
47         if check(x,i) then
48         begin
49             fill(x,i,1);
50             dfs(x+1,lt);
51             fill(x,i,0);
52         end;
53 end;
54 begin
55     assign(input,‘tile.in‘);reset(input);
56     assign(output,‘tile.out‘);rewrite(output);
57     readln(n,m);
58     for i:=0 to 1<<(2*m)-1 do
59     begin
60         for j:=1 to m do
61             if i and (1<<(m*2-j))>0 then a[1,j]:=1 else a[1,j]:=0;
62         for j:=1 to m do
63             if i and (1<<(m-j))>0 then a[2,j]:=1 else a[2,j]:=0;
64         dfs(1,i);
65     end;
66     dp[1][(1<<m-1)<<m]:=1;
67     for i:=2 to n+1 do
68         for j:=0 to 1<<(2*m)-1 do
69             for k:=0 to 1<<(2*m)-1 do
70                 dp[i][j]:=(dp[i][j]+dp[i-1][k]*g[k][j]) mod mo;
71     writeln(dp[n+1][(1<<m-1)<<m]);
72     close(input);
73     close(output);
74 end.

AC 代码

  1 #include <cstdio>
  2 #include <cstring>
  3 #define P 65521
  4
  5 #ifdef _WIN32
  6 #define ll "%I64d"
  7 #else
  8 #define ll "%lld"
  9 #endif
 10
 11 int m,M,ST,N,q[5000],h[5000],pos[5000];
 12 long long n,g[4096][4096],t[150][150];
 13 bool b[3][10],v1[5000],v2[5000];
 14
 15 struct matrix
 16 {
 17     long long a[150][150];
 18     matrix() {memset(a,0,sizeof(a));}
 19     void one() {for (int i=1;i<=N;++i) a[i][i]=1;}
 20     matrix& operator*=(const matrix &B)
 21     {
 22         memset(t,0,sizeof(t));
 23         for (int i=1;i<=N;++i)
 24             for (int j=1;j<=N;++j)
 25                 for (int k=1;k<=N;++k)
 26                     t[i][j]=(t[i][j]+a[i][k]*B.a[k][j])%P;
 27         memcpy(a,t,sizeof(a)); return *this;
 28     }
 29 }A,R;
 30
 31 bool can(int i,int j)
 32 {return i>=0&&i<3&&j>=0&&j<m&&!b[i][j];}
 33
 34 bool check(int k,int i)
 35 {
 36     switch (k)
 37     {
 38         case 1:return can(1,i)&&can(1,i+1)&&can(0,i);
 39         case 2:return can(1,i)&&can(1,i+1)&&can(2,i);
 40         case 3:return can(1,i)&&can(1,i-1)&&can(2,i);
 41         case 4:return can(1,i)&&can(1,i-1)&&can(0,i);
 42         case 5:return can(1,i)&&can(0,i)&&can(2,i)&&can(1,i+1);
 43         case 6:return can(1,i)&&can(2,i)&&can(1,i-1)&&can(1,i+1);
 44         case 7:return can(1,i)&&can(0,i)&&can(2,i)&&can(1,i-1);
 45         case 8:return can(1,i)&&can(0,i)&&can(1,i-1)&&can(1,i+1);
 46         default:return 0;
 47     }
 48 }
 49
 50 bool fill(int k,int i,int v)
 51 {
 52     switch (k)
 53     {
 54         case 1:return b[1][i]=b[1][i+1]=b[0][i]=v;
 55         case 2:return b[1][i]=b[1][i+1]=b[2][i]=v;
 56         case 3:return b[1][i]=b[1][i-1]=b[2][i]=v;
 57         case 4:return b[1][i]=b[1][i-1]=b[0][i]=v;
 58         case 5:return b[1][i]=b[0][i]=b[2][i]=b[1][i+1]=v;
 59         case 6:return b[1][i]=b[2][i]=b[1][i-1]=b[1][i+1]=v;
 60         case 7:return b[1][i]=b[0][i]=b[2][i]=b[1][i-1]=v;
 61         case 8:return b[1][i]=b[0][i]=b[1][i-1]=b[1][i+1]=v;
 62         default:return 0;
 63     }
 64 }
 65
 66 void dfs(int dep,int last)
 67 {
 68     if (dep>m)
 69     {
 70         for (int i=0;i<m;++i) if (!b[0][i]) return;
 71         int next=0;
 72         for (int i=2;i;--i)
 73             for (int j=m-1;j>=0;--j)
 74                 next=next*2+b[i][j];
 75         ++g[last][next]; return;
 76     }
 77     dfs(dep+1,last);
 78     for (int i=1;i<=8;++i)
 79         if (check(i,dep))
 80         {fill(i,dep,1); dfs(dep+1,last); fill(i,dep,0);}
 81 }
 82
 83 void bfs()
 84 {
 85     int l=0,r=0; q[++r]=ST; v1[ST]=1;
 86     while (l<r)
 87     {
 88         int x=q[++l];
 89         for (int y=0;y<M;++y)
 90             if (g[x][y]&&!v1[y]) {v1[y]=1; q[++r]=y;}
 91     }
 92     l=r=0; q[++r]=ST; v2[ST]=1;
 93     while (l<r)
 94     {
 95         int x=q[++l];
 96         for (int y=0;y<M;++y)
 97             if (g[y][x]&&!v2[y]) {v2[y]=1; q[++r]=y;}
 98     }
 99     for (int i=0;i<M;++i)
100         if (v1[i]&&v2[i]) {h[++N]=i; pos[i]=N;}
101     for (int i=0;i<M;++i)
102         for (int j=0;j<M;++j)
103             A.a[pos[i]][pos[j]]=g[i][j];
104 }
105
106 void pow(long long b)
107 {while (b) {if (b&1) R*=A; A*=A; b>>=1;}}
108
109 int main()
110 {
111     freopen("tile.in","r",stdin);
112     freopen("tile.out","w",stdout);
113     scanf(ll "%d",&n,&m); M=1<<(2*m); ST=(1<<m)-1;
114     for (int st=0;st<M;++st)
115     {
116         for (int i=0;i<m;++i) b[0][i]=(st>>i)&1;
117         for (int i=0;i<m;++i) b[1][i]=(st>>(i+m))&1;
118         dfs(0,st);
119     }
120     bfs(); R.one(); pow(n);
121     printf(ll "\n",R.a[pos[ST]][pos[ST]]);
122     fclose(stdin); fclose(stdout);
123     return 0;
124 }
时间: 2024-11-23 21:59:02

瓷砖铺放 (状压DP+矩阵快速幂)的相关文章

HDU 5434 Peace small elephant 状压dp+矩阵快速幂

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5434 Peace small elephant Accepts: 38 Submissions: 108 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) 问题描述 小明很喜欢国际象棋,尤其喜欢国际象棋里面的大象(只要无阻挡能够斜着走任意格),但是他觉得国际象棋里的大象太凶残了,于是他

POJ 3420 Quad Tiling 状压DP+矩阵快速幂

链接:http://poj.org/problem?id=3420 题意:给一个4*N(1 ≤ N ≤ 1e9)的矩形空间,并且给不限块数的1*2的多米诺骨牌,问是由多少种方式能把这个矩形空间填满. 思路:看到这种问题果断想到状压,虽然是在看矩阵的时候看到的这道题.dp[i][j]表示在第i行状态为j的情况下的填满方式数,j的二进制表示中0表示对应位置上一行的骨牌是竖放,或者对应位置的骨牌是横放,1则表示该行该位置的骨牌是竖放.由于N最大1e9所以O(n)的DP绝对超时,用矩阵快速幂来加速DP递

BZOJ 4000: [TJOI2015]棋盘( 状压dp + 矩阵快速幂 )

状压dp, 然后转移都是一样的, 矩阵乘法+快速幂就行啦. O(logN*2^(3m)) --------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define b(x) (1 <&l

poj 2411 Mondriaan&#39;s Dream 骨牌铺放 状压dp

题目链接 题意 用\(1\times 2\)的骨牌铺满\(H\times W(H,W\leq 11)\)的网格,问方案数. 思路 参考focus_best. 竖着的骨牌用\(\begin{pmatrix}0\\1\end{pmatrix}\)表示,横着的骨牌用\(\begin{pmatrix}1&1\end{pmatrix}\)表示. 则对于第\(i\)行,与之相容的第\(i-1\)行的状态需满足: 第\(i\)行是0的位置,第\(i-1\)行必须是1: 第\(i\)行是1的位置,第\(i-1\

『公交线路 状压dp 矩阵乘法加速』

公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的相邻两个 站台间距离不得超过Pkm. 在最终设计

POJ3420 Quad Tiling DP + 矩阵快速幂

题目大意是用1*2的骨牌堆积成4*N的矩形,一共有多少种方法,N不超过10^9. 这题和曾经在庞果网上做过的一道木块砌墙几乎一样.因为骨牌我们可以横着放,竖着放,我们假设以4为列,N为行这样去看,并且在骨牌覆盖的位置上置1,所以一共最多有16种状态.我们在第M行放骨牌的时候,第M+1行的状态也是有可能被改变的,设S(i,j)表示某一行状态为i时,将其铺满后下一行状态为j的方案书.考虑下如果我们让矩阵S和S相乘会有什么意义,考虑一下会发现S*S的意义当某行状态为i,接着其后面第2行的状态为j的可行

POJ3735 Training little cats DP,矩阵快速幂,稀疏矩阵优化

题目大意是,n只猫,有k个动作让它们去完成,并且重复m次,动作主要有三类gi,ei,s i j,分别代表第i只猫获得一个花生,第i只猫吃掉它自己所有的花生,第i只和第j只猫交换彼此的花生.k,n不超过100,m不超过1000,000,000,计算出最后每只猫还剩下多少个花生. 我们假设一个n维向量P,每个分量的值代表这n只猫所拥有的花生数,那么对于gi操作其实就是在第i维分量上加上1:对于ei,那就是在第i维分量上乘以0,说到这里,有木有感觉这很像3D坐标转化中的平移矩阵和缩放矩阵?没错,就是这

HDU 2294 Pendant (DP+矩阵快速幂降维)

HDU 2294 Pendant (DP+矩阵快速幂降维) ACM 题目地址:HDU 2294 Pendant 题意: 土豪给妹子做首饰,他有K种珍珠,每种N个,为了炫富,他每种珍珠都要用上.问他能做几种长度[1,N]的首饰. 分析: 1 ≤ N ≤ 1,000,000,000简直可怕. 首先想dp,很明显可以想到: dp[i][j] = (k-(j-1))*dp[i-1][j-1] + j*dp[i-1][j](dp[i][j]表示长度为i的并且有j种珍珠的垂饰有多少个) 然后遇到N太大的话,

HDU5863 cjj&#39;s string game(DP + 矩阵快速幂)

题目 Source http://acm.split.hdu.edu.cn/showproblem.php?pid=5863 Description cjj has k kinds of characters the number of which are infinite. He wants to build two strings with the characters. The lengths of the strings are both equal to n. cjj also def