hdu5731
【題意】題解from phile的空間給你乙個nm的棋盤,
我們用12或2*1(即橫著放或豎著放)的骨牌去填充這個棋盤。
問你有多少種填法,使得這個棋盤——
任意相鄰兩行或兩列之間都必須要有乙個骨牌橫跨。
也就是使得這個棋盤為穩定的。
先求出不考慮分割線的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...