传送门
题目描述
分析
我们去用二进制表示每个每个原料选或者没选,然后去维护各种信息就可以了,需要注意的是可能有两张披萨的原料相同,所以我们要维护一个最值还有一个次最值
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC option("arch=native","tune=native","no-zero-upper")
#pragma GCC target("avx2")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
int n,m;
int f1[N]; //维护每一个状态的最小值
int f2[N]; //维护每一个状态的次小值
ll f[N];
int a[N]; //维护每一个人的状态
int d1[N]; //维护每一个状态对应第几个
int d2[N]; //维护每一个状态对应第几个
int c[N]; //维护每一个对应的成功状态的答案
PII res[N]; //维护答案
bool check(int x,int y){
for(int i = 0;i < 9;i++){
int a = x & 1;
int b = y & 1;
if(b && !a) return false;
x >>= 1;
y >>= 1;
}
return true;
}
int main(){
scanf("%d%d",&n,&m);
memset(f1,0x3f,sizeof f1);
memset(f2,0x3f,sizeof f2);
memset(f,0x3f,sizeof f);
for(int i = 1;i <= n;i++){
int num;
scanf("%d",&num);
int ans = 0;
for(int j = 1;j <= num;j++){
int x;
scanf("%d",&x);
ans += (1 << (x - 1));
}
a[i] = ans;
}
for(int i = 1;i <= m;i++){
int ppp,num;
scanf("%d%d",&ppp,&num);
int ans = 0;
for(int j = 1;j <= num;j++){
int x;
scanf("%d",&x);
ans += (1 << (x - 1));
}
if(f1[ans] > ppp){
f2[ans] = f1[ans];
f1[ans] = ppp;
d2[ans] = d1[ans];
d1[ans] = i;
}
else if(f2[ans] > ppp) {
f2[ans] = ppp;
d2[ans] = i;
}
}
for(int i = 0;i < 1 << 9;i++)
for(int j = 0;j < 1 << 9;j++){
if(i == j){
if(f1[i] == INF || f2[i] == INF) continue;
ll sum = f1[i] * 1ll + f2[i] * 1ll;
if(f[i] > sum){
f[i] = sum;
res[i] = {
d1[i],d2[i]};
}
}
else{
if(f1[i] == INF || f1[j] == INF) continue;
int k = i | j;
ll sum = f1[i] * 1ll + f1[j] * 1ll;
if(f[k] > sum){
f[k] = sum;
res[k] = {
d1[i],d1[j]};
}
}
}
for(int i = 0;i < 1 << 9;i++){
if(f[i] > 2000000000) continue;
int s = 0;
for(int j = 1;j <= n;j++)
if(check(i,a[j])) s++;
if(c[s] == 0 || f[c[s]] > f[i])
c[s] = i;
}
int ans = 0;
for(int i = n;~i;i--){
if(c[i]){
ans = i;
break;
}
}
printf("%d %d\n",min(res[c[ans]].first,res[c[ans]].second),max(res[c[ans]].first,res[c[ans]].second));
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/