[Algo] 状压dp2
1. 每个人戴不同帽子的方案数
// 1. 每个人戴不同帽子的方案数
// https://leetcode.cn/problems/number-of-ways-to-wear-different-hats-to-each-other/
int func1(int n, int m, vector<vector<int>>& people, int status, int cur, vector<vector<int>>& dp) {
if (status == (1 << n) - 1) return 1;
if (cur > m) return 0;
if (dp[status][cur] != -1) return dp[status][cur];
int ans = func1(n, m, people, status, cur + 1, dp) % MOD;
for (int person : people[cur]) {
if ((status & (1 << person)) == 0) {
ans = (ans + func1(n, m, people, status ^ (1 << person), cur + 1, dp)) % MOD;
}
}
dp[status][cur] = ans;
return ans;
}
int func2(int n, int m, vector<int>& people, int status, int cur, vector<vector<int>>& dp) {
if (status == (1 << n) - 1) return 1;
if (cur > m) return 0;
if (dp[status][cur] != -1) return dp[status][cur];
int ans = func2(n, m, people, status, cur + 1, dp) % MOD, like_status = people[cur], rightOne;
while (like_status) {
rightOne = like_status & -like_status;
if ((status & rightOne) == 0) {
ans = (ans + func2(n, m, people, status ^ rightOne, cur + 1, dp)) % MOD;
}
like_status ^= rightOne;
}
dp[status][cur] = ans;
return ans;
}
int numberWays(vector<vector<int>>& hats) {
int n = hats.size(), m = 0;
for (int i = 0; i < n; i++)
for (int e : hats[i]) m = max(m, e);
//vector<vector<int>> people(m + 1);
vector<int> people(m + 1);
for (int i = 0; i < n; i++)
for (int e : hats[i]) people[e] |= (1 << i);
vector<vector<int>> dp(1 << n, vector<int>(m + 1, -1));
return func2(n, m, people, 0, 1, dp);
}
2. 好子集的数目
// 2. 好子集的数目
// https://leetcode.cn/problems/the-number-of-good-subsets/
int own[31] = {
0b0000000000, // 0
0b0000000000, // 1
0b0000000001, // 2
0b0000000010, // 3
0b0000000000, // 4
0b0000000100, // 5
0b0000000011, // 6
0b0000001000, // 7
0b0000000000, // 8
0b0000000000, // 9
0b0000000101, // 10
0b0000010000, // 11
0b0000000000, // 12
0b0000100000, // 13
0b0000001001, // 14
0b0000000110, // 15
0b0000000000, // 16
0b0001000000, // 17
0b0000000000, // 18
0b0010000000, // 19
0b0000000000, // 20
0b0000001010, // 21
0b0000010001, // 22
0b0100000000, // 23
0b0000000000, // 24
0b0000000000, // 25
0b0000100001, // 26
0b0000000000, // 27
0b0000000000, // 28
0b1000000000, // 29
0b0000000111 // 30
};
int func3(vector<int>& cnt, int cur, int status, vector<vector<int>>& dp) {
if (dp[status][cur] != -1) return dp[status][cur];
int ans;
if (cur == 1) {
ans = 0;
if (status == 0) {
ans = 1;
for (int i = 0; i < cnt[cur]; i++) ans = (ans << 1) % MOD;
}
} else {
ans = func3(cnt, cur - 1, status, dp);
if (own[cur] != 0 && cnt[cur] != 0 && (own[cur] & status) == own[cur]) {
ans = (ans + (long)func3(cnt, cur - 1, status ^ own[cur], dp) * cnt[cur]) % MOD;
}
}
dp[status][cur] = ans;
return ans;
}
int numberOfGoodSubsets(vector<int>& nums) {
vector<int> cnt(31);
for (int num : nums) {
cnt[num]++;
}
int limit = 1 << 10;
int ans = 0;
vector<vector<int>> dp(limit, vector<int>(31, -1));
for (int i = 1; i < limit; i++) {
ans = (ans + func3(cnt, 30, i, dp)) % MOD;
}
return ans;
}
*3. 分配重复整数
// *3. 分配重复整数
// https://leetcode.cn/problems/distribute-repeating-integers/
// 时间复杂度为O(n * 3^m), n为nums中不同数字的个数, m为订单数
bool func4(vector<int>& cnt, vector<int>& sum, int status, int index, vector<vector<int>>& dp) {
if (status == 0) return true;
if (index == cnt.size()) return false;
if (dp[status][index] != 0) return dp[status][index] == 1;
bool ans = false;
// 枚举status的所有真子集
for (int j = status; j > 0; j = (j - 1) & status) {
if (sum[j] <= cnt[index] && func4(cnt, sum, status ^ j, index + 1, dp)) {
ans = true;
break;
}
}
if (!ans) {
ans = func4(cnt, sum, status, index + 1, dp);
}
dp[status][index] = ans == true ? 1 : -1;
return ans;
}
bool canDistribute(vector<int>& nums, vector<int>& quantity) {
sort(nums.begin(), nums.end());
vector<int> cnt;
cnt.push_back(1);
int n = nums.size();
for (int i = 1; i < n; i++) {
if (nums[i] == nums[i - 1]) cnt[cnt.size() - 1]++;
else cnt.push_back(1);
}
int m = quantity.size();
vector<int> sum(1 << m);
// 下面这个枚举是生成quantity中的每个子集,所需要数字的个数
for (int i = 0, v, h; i < m; i++) {
v = quantity[i];
h = 1 << i;
for (int j = 0; j < h; j++) {
sum[h | j] = sum[j] + v;
}
}
vector<vector<int>> dp(1 << m, vector<int>(cnt.size()));
return func4(cnt, sum, (1 << m) - 1, 0, dp);
}