題解 與多公尺諾有關的插頭DP

2021-09-24 04:26:53 字數 4594 閱讀 3725

hdu5731

【題意】

給你乙個nm的棋盤,

我們用12或2*1(即橫著放或豎著放)的骨牌去填充這個棋盤。

問你有多少種填法,使得這個棋盤——

任意相鄰兩行或兩列之間都必須要有乙個骨牌橫跨。

也就是使得這個棋盤為穩定的。

題解from phile的空間

先求出不考慮分割線的n*m棋盤的覆蓋方案數記為f[n][m]

然後列舉列分割線的狀態(狀壓),計算此時不存在行分割線的方案數

求出這個我們就可以用容斥原理算出答案了

怎麼算在列分割線確定的情況下,不存在行分割線的方案數呢?

記s[i]=f[i][a1]f[i][a2]…表示在有i行不考慮行分割線且列分割線分成a1,a2…ak塊的方案數

則到第i行不存在行分割線的方案數g[i]=s[i]-∑ g[j]*s[i-j] (1<=j通過在第乙個出現不合法位置來減去不合法,達到不重不漏的目的。是很常用的方法。

本題對列容斥,而對行用這種方法直接算出準確值

#include

using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)

#define repd(i,r,l) for(register int i = r ; i >= l ; i--)

#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)

#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))

#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))

#define pb push_back

#define prev prev_

#define stack stack_

#define mp make_pair

#define fi first

#define se second

#define lowbit(x) ((x)&(-(x)))

typedef

long

long ll;

typedef

long

double ld;

typedef

unsigned

long

long ull;

typedef pair<

int,

int> pr;

const ld inf =

2e18

;const

int maxn =

100020

;const ll mod =

1e9+7;

ll z[20]

,ans[20]

[20],g[20]

,f[20][

20],a[20];

unordered_map <

int,ll> h[2]

;int now,last;

inline

void

add(ll &x,ll y)

void

calc_f()

int up =

(s >>

(j -1)

)&1, left =

(s >> j)&1

;int cur = s -

(up <<

(j -1)

)-(left << j);if

( up && left )

continue;if

( up || left )

else}}

} f[n][16

]= h[now][0

];}//for (int i = 1 ; i <= 16 ; i++)

intsplit

(int s,

int m)

} a[

++k]

= m - last -1;

return k;

}void

calc_ans()

}}}void

init()

intmain()

bzoj 1435: [zjoi2009]多公尺諾骨牌

本題只是多了障礙的限制,使得需要記錄任意子矩陣的覆蓋方案數。

bzoj竟然連unordered_map都不支援,編譯器真的太老了, 本地過了對拍。懶得寫hashmap

#include

using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)

#define repd(i,r,l) for(register int i = r ; i >= l ; i--)

#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)

#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))

#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))

#define pb push_back

#define prev prev_

#define stack stack_

#define mp make_pair

#define fi first

#define se second

#define lowbit(x) ((x)&(-(x)))

typedef

long

long ll;

typedef

long

double ld;

typedef

unsigned

long

long ull;

typedef pair<

int,

int> pr;

const ld inf =

2e18

;const

int maxn =

100020

;const

int mod =

19901013

;int z[20]

[20],ans[20]

[20],g[20]

,f[20][

20][20

][20]

,a[20];

char ch[20]

[20];

unordered_map <

int,

int> h[2]

;unordered_map <

int,

int>

::iterator it;

int now,last,n,m;

inline

void

add(

int&x,

int y)

void

calc_f()

int up =

(s >>

(j - l))&

1, left =

(s >>

(j - l +1)

)&1;

int cur = s -

(up <<

(j - l))-

(left <<

(j - l +1)

);if( up && left )

continue;if

( up || left )

else

add(h[now]

[cur]

,d);}}

}}f[l]

[r][i]

[m]= h[now][0

];}}

//for (int i = 1 ; i <= n ; i++)

intsplit

(int s,

int m)

} a[

++k]

= m - last -1;

return k;

}void

calc_ans()

g[n]

= z[1]

[n];

for(

int i =

1; i < n ; i++

) g[n]

=(g[n]

-(ll)g[i]

* z[i +1]

[n]% mod + mod)

% mod;

add(ans[n]

[m],g[n]*(

!(k &1)

?(-1

):1)

);}// for (int i = 1 ; i <= n ; i++)}}

void

init()

intmain()

多公尺諾骨牌問題,狀態壓縮dp

題目描述 用1 2 的矩形通過組合拼成大矩形,求拼成指定的大矩形有幾種拼法。首先 我們先求用1 2 的矩形拼成 n m的矩形有多少種拼法 當n m為奇數時,一定是不會拼出來的,因為想要拼出來就需要整數倍的小矩形數目。為了加速演算法,要把m,n中小的那個當做列 分兩個步驟 1 先求出相鄰兩行的轉化關係...

P1282 多公尺諾骨牌 DP

多公尺諾骨牌有上下2個方塊組成,每個方塊中有1 6個點。現有排成行的 上方塊中點數之和記為s1,下方塊中點數之和記為s2,它們的差為 s1 s2 例如在圖8 1中,s1 6 1 1 1 9,s2 1 5 3 2 11,s1 s2 2。每個多公尺諾骨牌可以旋轉180 使得上下兩個方塊互換位置。程式設計...

P1282 多公尺諾骨牌 DP

題目大意 題解當知道 總和 及 單行的和 就可以算出差值的大小 1 2 3 4 單行和l 10 8 7 6 5 總和s 36 則上下行的差值為 l s l include define inf 0x3f3f3f3f using namespace std int n,a 1005 b 1005 dp...