题意
给你 n n n个长度为 m m m的数组,每个数组都有一个价值 w i w_i wi,让你选出两个数组他们没有交集且价值和最大,如果没有输出 − 1 -1 −1。
2 ≤ n ≤ 1 e 5 , 1 ≤ m ≤ 5 , 1 ≤ a i , j , w i ≤ 1 e 9 2\le n\le 1e5,1\le m\le 5,1\le a_{i,j},w_i\le 1e9 2≤n≤1e5,1≤m≤5,1≤ai,j,wi≤1e9
思路
看到 m m m很小,很容易向状压地方靠,假设 a a a很小,那么这个题就很简单了,我们将每个数组状压成一个二进制,让后 s o s d p sosdp sosdp求一下子集最小值,让后遍历即可获得答案。
但是这个题 a a a高达 1 e 9 1e9 1e9,但是我们发现其最终答案是一对之间,那么我们将 a a a随机映射到 0 − 15 0-15 0−15之间的某个数,注意同一个数一定映射到相同数,不同数可能映射到相同数,我们发现这样操作后对于答案的两个数组他们都映射到不同数上的概率为 0.0188 0.0188 0.0188,这也是答案正确的概率,虽然这个数很小,但是我们运行 200 200 200次,期望概率就达到 2 2 2以上了,基本可以认为是正确的。
复杂度 P ( 250 ∗ 16 ∗ ( 1 < < 16 ) ) P(250*16*(1<<16)) P(250∗16∗(1<<16))
t r i c k : trick: trick:遇到很大的数可以将其映射到小范围的数上进行乱搞。
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;
const int N=500010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;
int n,m;
int a[N][6],w[N];
int b[N][6];
int f[1<<21];
mt19937 rnd(time(0));
int mp[N],id[N];
vector<int>v;
template <class T>
bool read(T &ret)//输入
{
char c;
int sgn;
T bit=0.1;
if(c=getchar(), c==EOF)
return 0;
while(c!='-' && c!='.' && (c<'0' || c>'9'))
c=getchar();
sgn=(c=='-')? -1:1;
ret=(c=='-')? 0:(c-'0');
while(c=getchar(), c>='0' && c<='9')
ret=ret*10+(c-'0');
if(c==' ' || c=='\n')
{
ret*=sgn;
return 1;
}
while(c=getchar(), c>='0' && c<='9')
ret+=(c-'0')*bit, bit/=10;
ret*=sgn;
return 1;
}
int find(int x) {
return lower_bound(v.begin(),v.end(),x)-v.begin();
}
void solve() {
read(n); read(m);
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
read(a[i][j]);
v.pb(a[i][j]);
}
read(w[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
a[i][j]=find(a[i][j]);
}
}
srand(20000926);
int ans=2e9+7;
for(int _=1;_<=250;_++) {
for(int i=0;i<N;i++) id[i]=rand()%16;
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++) {
int state=0;
for(int j=1;j<=m;j++) {
b[i][j]=id[a[i][j]];
state|=1<<b[i][j];
}
f[state]=min(f[state],w[i]);
}
int all=1<<16;
for(int j=0;j<16;j++) {
for(int i=0;i<all;i++) {
if(!(i>>j&1)) f[i|(1<<j)]=min(f[i|(1<<j)],f[i]);
}
}
for(int i=0;i<all;i++) {
int j=(all-1)^i;
if(f[i]!=0x3f3f3f3f&&f[j]!=0x3f3f3f3f) ans=min(ans,f[i]+f[j]);
}
}
printf("%d\n",ans==2e9+7? -1:ans);
}
int main() {
LL f1,f2;
f1=f2=1;
for(int i=15;i>=15-10+1;i--) f1*=i;
for(int i=1;i<=10;i++) f2*=15;
printf("%.10f\n",1.0*f1/f2);
int _=1;
while(_--) {
solve();
}
return 0;
}