hdu 5766 Filling 轮廓线dp burnside

Filling

题目连接:

http://acm.hdu.edu.cn/showproblem.php?pid=5766

Description

The board is a rectangle of unit cells with N rows and N columns. At first, cells are empty. ?? has infinite blocks with the size of 2*2. ?? can put blocks in the board as long as no two blocks overlap. ?? wants to know how many different ways to fill the board, not necessary full. Two ways are consider same if they are same by rotating.

Input

The first line of the input gives the number of test cases T; T test cases follow.
Each test case consists of one integers N, as described on the description above.

limits
T <= 20
1 <= N <= 20

Output

For each test case, output one line containing “Case #x: y” (without quotes) , where x is the test case number (starting from 1) and y is the answer you get for that case, since the answer may be too large, you should output the it modulo 1000000007 (1e9 + 7).

Sample Input

5
1
2
3
4
5

Sample Output

Case #1: 1
Case #2: 2
Case #3: 2
Case #4: 12
Case #5: 84

hint

In forth case, we have 12 different ways.(0 denotes unfilled,1 denoted filled)
0000   1100   0110   0000   1111   0000   1100   1100   1100   1111   1111   1111
0000   1100   0110   0110   1111   1111   1111   1100   1100   1111   1111   1111
0000   0000   0000   0110   0000   1111   0011   0011   0110   1100   0110   1111
0000   0000   0000   0000   0000   0000   0000   0011   0110   1100   0110   1111

题意:

n*n的格子里放2*2的块,相互不重叠,问旋转同构下的方案数

题解:

旋转同构很好判,根据bunrside引理,就是转0,90,180,270度下旋转不变的情况数求和除4。转90和转270是一样的,所以一共只有三种情况。

转0度:

  就是一个n*n的格子,2*2的块不能放出限制,直接画出mask,轮廓线dp

  以4*4为例,它的边界mask为:

  111111

  100001

  100001

  100001

  100001

  111111

转90度:

  转90度的情况最为复杂,总的来说就是枚举中间十字放2*2的情况,再对一个角落跑轮廓线dp。以方便考虑,我们考虑右下角的1/4块

  n为奇数时,中间的m[n/2+1][n/2+1]不能放,边界左上角不会冲突,那么直接枚举2n/2的边界放置情况,顺便判是否两个两个在一起。

  n为偶数时,如果有一个放在边界左上角,必然冲突不能旋转同构。所有的合法情况是不管那最左边的那个,直接枚举2n/2的边界放置情况,顺便判edge>>1是否两个两个在一起。

  0000  0000

  0011  0110

  0011  0110

  0000  0000

转180度

  我考虑下半面

  n为奇数时,中间的m[n/2+1][n/2+1]不能放,注意边界左边低一格

  n为偶数时,有两种情况,枚举边界的时候要注意,1是edge合法,2是edge>>1合法

  11111      0000  0000

  11100    0110  0011

  00000    0110  0011

  00000    0000  0000

写轮廓线的时候有个地方要注意mask[X+1][t]

void dfs(LL st,int t,LL dp)    //st之前状态,code上行状态,mask边界,当前在(X,t)
{
    if(t>=n+1)return;
    if(!mask[X][t]&&!mask[X][t+1]&&!code[t]&&!code[t+1]&&!mask[X+1][t])
    {
        hm[f^1].push(st^(1<<t)^(1<<(t+1)),dp);
        dfs(st^(1<<t)^(1<<(t+1)),t+2,dp);
    }
    dfs(st,t+1,dp);
}

最后写完打表就好了

第一次写轮廓线,写了很久,各种坑。。

代码

  1 //#include <bits/stdc++.h>
  2 #include <stdio.h>
  3 #include <iostream>
  4 #include <string.h>
  5 #include <math.h>
  6 #include <stdlib.h>
  7 #include <limits.h>
  8 #include <algorithm>
  9 #include <queue>
 10 #include <vector>
 11 #include <set>
 12 #include <map>
 13 #include <stack>
 14 #include <bitset>
 15 #include <string>
 16 #include <time.h>
 17 using namespace std;
 18 long double esp=1e-11;
 19 //#pragma comment(linker, "/STACK:1024000000,1024000000")
 20 #define fi first
 21 #define se second
 22 #define all(a) (a).begin(),(a).end()
 23 #define cle(a) while(!a.empty())a.pop()
 24 #define mem(p,c) memset(p,c,sizeof(p))
 25 #define mp(A, B) make_pair(A, B)
 26 #define pb push_back
 27 #define lson l , m , rt << 1
 28 #define rson m + 1 , r , rt << 1 | 1
 29 typedef long long int LL;
 30 const long double PI = acos((long double)-1);
 31 const LL INF=0x3f3f3f3fll;
 32 const int MOD =1000000007ll;
 33 const int maxn=11000;
 34
 35 LL inv4=250000002ll;
 36 const int MAXD=15;
 37 const int HASH=30007;
 38 const int STATE=1<<20;
 39 struct HASHMAP
 40 {
 41     int head[HASH],next[STATE],sz;
 42     LL state[STATE];
 43     LL dp[STATE];
 44     void init()
 45     {
 46         sz=0;
 47         memset(head,-1,sizeof(head));
 48     }
 49     void push(LL st,LL ans)
 50     {
 51         int i;
 52         int h=st%HASH;
 53         for(i=head[h];i!=-1;i=next[i])//这里要注意是next
 54           if(state[i]==st)
 55           {
 56               dp[i]=(dp[i]+ans)%MOD;
 57               //dp[i]+=ans;
 58               return;
 59           }
 60         state[sz]=st;
 61         dp[sz]=ans;
 62         next[sz]=head[h];
 63         head[h]=sz++;
 64     }
 65 }hm[2];
 66 int n;
 67 bool mask[22][22];
 68 int f,code[22],X;
 69 void decode(LL state)
 70 {
 71     for(int x=1;x<=n;x++)
 72         code[x]=((state>>x)&1);
 73     code[0]=code[n+1]=1;
 74 }
 75 void dfs(LL st,int t,LL dp)
 76 {
 77     if(t>=n+1)return;
 78     if(!mask[X][t]&&!mask[X][t+1]&&!code[t]&&!code[t+1]&&!mask[X+1][t])
 79     {
 80         hm[f^1].push(st^(1<<t)^(1<<(t+1)),dp);
 81         dfs(st^(1<<t)^(1<<(t+1)),t+2,dp);
 82     }
 83     dfs(st,t+1,dp);
 84 }
 85 bool check(int s,int l)
 86 {
 87     for(int x=0;x<l;x++)
 88         if((s>>x)&1)
 89         {
 90             if((s>>(x+1))&1)
 91             {
 92                 x++;
 93                 continue;
 94             }
 95             else
 96                 return 0;
 97         }
 98     return 1;
 99 }
100 LL lkx(int a,int b,int n)
101 {
102     hm[0].init();
103     hm[0].push(0,1);
104     f=0;
105     for(int x=a;x<=n;x++)
106     {
107         X=x;
108         hm[f^1].init();
109         for(int k=0;k<hm[f].sz;k++)
110         {
111             decode(hm[f].state[k]);
112             LL dp=hm[f].dp[k];
113             hm[f^1].push(0,dp);
114             dfs(0,b,dp);
115         }
116         f^=1;
117     }
118     for(int k=0;k<hm[f].sz;k++)
119         if(hm[f].state[k]==0)
120             return hm[f].dp[k]%MOD;
121 }
122 int main()
123 {
124     //freopen("in.txt", "r", stdin);
125     //freopen("inlay.in", "r", stdin);
126     //freopen("out.txt", "w", stdout);      //%I64d
127     //vector<int>::iterator iter;
128     //memset(m,0,sizeof(int));
129     //for(int x=1;x<=n;x++)
130     //for(int y=1;y<=n;y++)
131     //scanf("%d",&a);
132     //printf("%d\n",ans);
133     for(n=1;n<=20;n++)
134     {
135         //***********0
136         mem(mask,0);
137         for(int x=0;x<=n+1;x++)
138         {
139             if(x==0||x==n+1)
140                 for(int y=0;y<=n+1;y++)
141                     mask[x][y]=1;
142             else
143                 mask[x][0]=mask[x][n+1]=1;
144         }
145         LL ans=0;
146         ans+=lkx(1,1,n);
147         //printf("0 %d %lld\n",n,ans);    ans=0;
148         //***********90 270
149         for(int s=0;s<(1<<(n/2));s++)
150         {
151             int odd=n&1;
152             if(odd&&!check(s,n/2))continue;
153             if(!odd&&!check(s>>1,n/2-1))continue;
154             mem(mask,0);
155             for(int x=n/2;x<=n+1;x++)
156             {
157                 if(x==n/2||x==n+1)
158                     for(int y=0;y<=n+1;y++)
159                         mask[x][y]=1;
160                 else
161                     mask[x][n/2+odd]=mask[x][n+1]=1;
162             }
163             for(int x=n/2+1+odd;x<=n;x++)
164                 mask[x][n/2+1+odd]=mask[n/2+1][x]=(s>>(x-n/2-1-odd))&1;
165             ans+=lkx(n/2+1,n/2+1+odd,n)*2;
166         }
167         //printf("1 %d %lld\n",n,ans);    ans=0;
168         //***********180
169         for(int s=0;s<(1<<(n/2));s++)
170         {
171             int odd=n&1;
172             if(odd&&!check(s,n/2))continue;
173             if(!odd&&!(check(s,n/2)||check(s>>1,n/2-1)))continue;
174             mem(mask,0);
175             for(int x=n/2;x<=n+1;x++)
176             {
177                 if(x==n/2||x==n+1)
178                     for(int y=0;y<=n+1;y++)
179                         mask[x][y]=1;
180                 else
181                     mask[x][0]=mask[x][n+1]=1;
182             }
183             if(odd)
184             for(int x=1;x<=n/2+1;x++)
185                 mask[n/2+1][x]=1;
186             for(int x=n/2+1+odd;x<=n;x++)
187                 mask[n/2+1+odd][n+1-x]=mask[n/2+1][x]=(s>>(x-n/2-1-odd))&1;
188             ans+=lkx(n/2+1,1,n);
189         }
190         //printf("3 %d %lld\n",n,ans);
191         printf(",%I64d",ans%MOD*inv4%MOD);
192     }
193
194     return 0;
195 }

值为

LL ans[25]={1,1,2,2,12,84,1641,50788,3183091,338785462,429880385,948920428,392930107,842384602,
36468923,534250025,693507546,311288183,320259213,232751393,866290697};

2016-07-31
时间: 2024-08-03 20:06:23

hdu 5766 Filling 轮廓线dp burnside的相关文章

hdu 4804 Campus Design 轮廓线dp

题意: 给出一个n*m的01矩阵,其中要求把矩阵里面的1用1*1或1*2的砖块铺满,矩阵里面的0为障碍物,问使用1*1的砖块数>=c && <=d 的方案有多少种. 限制: 1 <= n <= 100; 1 <= m <= 10; 1 <= c <= d <= 20; 思路: 因为 1 <= m <= 10 所以可以采用轮廓线dp, 具体状态解释在代码中说明. /*hdu 4804 Campus Design 轮廓线dp 题

POJ 2411 Mondriaan&#39;s Dream( 轮廓线dp )

最普通的轮廓线dp... 复杂度O(nm2min(n, m)) -------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; #define b(x) (1 << (x)) const in

2013 ACM-ICPC亚洲区域赛南京站C题 题解 轮廓线DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4804 题目大意 给你一个 \(n \times m\) 的矩形区域.你需要用 \(1 \times 1\) 和 \(1 \times 2\) 的砖块铺满这个区域,且满足如下要求: 所有的砖块可以竖着放或横着放: 砖角要放在格点上: \(1 \times 1\) 的砖不能少于 \(C\) 块也不能多于 \(D\) 块, \(1 \times 2\) 的砖没有数量限制. 有些方格在一开始就已经被填充了,

HDU 4960 (水dp)

Another OCD Patient Problem Description Xiaoji is an OCD (obsessive-compulsive disorder) patient. This morning, his children played with plasticene. They broke the plasticene into N pieces, and put them in a line. Each piece has a volume Vi. Since Xi

HDU 1087 &amp;&amp; POJ 2533(DP,最长上升子序列).

~~~~ 两道题的意思差不多,HDU上是求最长上升子序列的和,而POJ上就的是其长度. 貌似还有用二分写的nlogn的算法,不过这俩题n^2就可以过嘛.. ~~~~ 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1087 http://poj.org/problem?id=2533 ~~~~ HDU1087: #include<cstdio> #include<cstring> #include<algorithm> #

hdu 2296 aC自动机+dp(得到价值最大的字符串)

Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3180    Accepted Submission(s): 1033 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a rom

hdu 2457 AC自动机+dp

DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2004    Accepted Submission(s): 1085 Problem Description Biologists finally invent techniques of repairing DNA that contains segments c

POJ 3254 Corn Fields (状压DP,轮廓线DP)

题意: 有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)? 思路: 明显的状压DP啦,只是怎样压缩状态?跟轮廓线DP一样,按格子为单位来设计状态,一个状态只需要表示到其上方和左方的格子,所以最多只需要保存min(n,m)个01状态就行了(可以尝试旋转一下矩阵),最多需要12位.用哈希表来做会比较快吧,不用去考虑无效的状态,比如出现相邻两个1. 1 //#include <bits/stdc++.

轮廓线DP POJ3254

补了一发轮廓线DP,发现完全没有必要从右往左设置状态,自然一点: 5 6 7 8 9 1 2 3 4 如此设置轮廓线标号,转移的时候直接把当前j位改成0或者1就行了.注意多记录些信息对简化代码是很有帮助的,尤其对于我这种代码经常错的一塌糊涂的人来说.. 呆马: #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath>