題意 :
- 其他條件和上題相同
- 這里已知n個點,給定每個點的編號和顏色
- 求這個樹的合法染色方案,取模1e9 + 7
思路 :
- 首先預處理d[c][k]d[c][k]d[c][k]表示根結點顏色為c,深度為k的滿二叉樹的方案
- 0 <= c < 6, 1 <= k <= 60,數據范圍較小,因此可以很快預處理
- 如果一顆子樹,所有點都沒有顏色,那么可以用預處理的數組直接O(1)O(1)O(1)給出方案數
- 因此我們只需要關注有帶色點的子樹
- 由于只有2000個點有顏色,k<=60,因此最多2000*60個點是我們需要關注的
- 我們對這2000*60個點單獨記憶化搜索即可
- d2[id][c]d2[id][c]d2[id][c]表示id點顏色為c,子樹的方案數
- d[][]d[][]d[][]和d2[][]d2[][]d2[][]的轉移 :
- 枚舉左右子結點的顏色即可
- 注意思考為什么需要映射
#include <iostream>
#include <cstring>
#include <map>using namespace std
;typedef long long ll
;const ll mod
= 1e9 + 7;ll n
, k
;
ll lim
[10][10];
ll d
[10][66];
ll d2
[2222 * 66][6];
map
<ll
, ll
> col
;
map
<ll
, bool> mark
;
map
<ll
, ll
> idx
;
ll num
;
map
<char, ll
> c_mp
= {{'w', 0},{'y', 1},{'g', 2},{'b', 3},{'r', 4},{'o', 5},
};
void init()
{lim
[0][0] = lim
[0][1] = 1;lim
[1][0] = lim
[1][1] = 1;lim
[2][3] = lim
[2][2] = 1;lim
[3][2] = lim
[3][3] = 1;lim
[4][5] = lim
[4][4] = 1;lim
[5][4] = lim
[5][5] = 1;
}
ll
dp_dfs(ll c
, ll k
)
{if (k
== 1) return 1; if (d
[c
][k
] != -1) return d
[c
][k
]; d
[c
][k
] = 0; for (int i
= 0; i
< 6; i
++ ) {if (lim
[c
][i
]) continue; for (int j
= 0; j
< 6; j
++ ) {if (lim
[c
][j
]) continue;d
[c
][k
] = (d
[c
][k
] + dp_dfs(i
, k
- 1) * dp_dfs(j
, k
- 1) % mod
) % mod
;}}return d
[c
][k
];
}
ll
dfs(ll c
, ll k
, ll id
)
{if (col
.count(id
) && col
[id
] != c
) return 0; if (k
== 1) return 1; if (!mark
[id
]) return d
[c
][k
];if (!idx
.count(id
)) idx
[id
] = ++ num
; ll x
= idx
[id
]; if (d2
[x
][c
] != -1) return d2
[x
][c
]; d2
[x
][c
] = 0; ll l
= id
<< 1, r
= id
<< 1 | 1; for (int i
= 0; i
< 6; i
++ ){if (lim
[c
][i
]) continue;for (int j
= 0; j
< 6; j
++ ){if (lim
[c
][j
]) continue;d2
[x
][c
] = (d2
[x
][c
] + dfs(i
, k
- 1, l
) * dfs(j
, k
- 1, r
) % mod
) % mod
;}}return d2
[x
][c
];
}void solve()
{init(); cin
>> k
>> n
;memset(d
, -1, sizeof d
);memset(d2
, -1, sizeof d2
);for (int i
= 0; i
< 6; i
++ )dp_dfs(i
, k
);for (int i
= 1; i
<= n
; i
++ ){ll x
; string s
;cin
>> x
>> s
;col
[x
] = c_mp
[s
[0]]; while (x
) {mark
[x
] = 1;x
/= 2;}}ll ans
= 0;for (int i
= 0; i
< 6; i
++ )ans
= (ans
+ dfs(i
, k
, 1)) % mod
;cout
<< ans
<< endl
;
}int main()
{ios
::sync_with_stdio(false); cin
.tie(0); cout
.tie(0);int _
= 1;
while (_
-- ){solve();}return 0;
}
與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的E2. Rubik‘s Cube Coloring (hard version) dp,满二叉树(2300)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。