Description
给定四个集合S1,S2,S3,S4。
每次从四个集合里分别选出一个数组成可重集合S。
问可形成的
Solution
考虑这样的状态:
当前已考虑前i种元素,从
把同一元素在四个集合中的出现情况压成20,21,22,23。
再考虑把16种情况压成216。
每次只要枚举本次要选取的状态,从当前状态的子集转移,保证不会从同一集合中多选就好了。
#include <bits/stdc++.h>
using namespace std;
class MealPlan{
public:
map<int, long long> mp, dp, dp1;
long long ans;
inline int BitCount(int x) {
int cnt = 0;
for (; x; x -= x & -x) ++cnt;
return cnt;
}
long long countDistinct(vector<int> a, vector<int> b, vector<int> c, vector<int> d) {
for (int i : a) mp[i] |= 1;
for (int i : b) mp[i] |= 2;
for (int i : c) mp[i] |= 4;
for (int i : d) mp[i] |= 8;
dp1[1] = 1;
for (auto i: mp) {
dp = dp1;
int s = i.second;
for (auto j: dp1) {
int x = j.first;
long long res = j.second;
for (int k = 1; k <= 4; k++) {
int y = 0;
for (int t = s; t; t = s & (t - 1)) {
if (BitCount(t) == k) {
for (int p = 0; p < 16; p++)
if (!(p & t) && (x >> p & 1))
y |= 1 << (p | t);
}
}
if (y) dp[y] += res;
}
}
dp1 = dp;
}
for (auto x: dp)
if (x.first >> 15 & 1)
ans += x.second;
return ans;
}
};
MealPlan S;
vector<int> p[4];
int n, x;
int main(void) {
freopen("1.in", "r", stdin);
for (int i = 0; i < 4; i++) {
cin >> n;
for (int j = 0; j < n; j++) {
cin >> x; p[i].push_back(x);
}
}
cout << S.countDistinct(p[0], p[1], p[2], p[3]) << endl;
return 0;
}