文章目录
- 题意
- 思路
传送门
题意
给你nnn个长度为mmm的数组,每个数组都有一个价值wiw_iwi,让你选出两个数组他们没有交集且价值和最大,如果没有输出−1-1−1。
2≤n≤1e5,1≤m≤5,1≤ai,j,wi≤1e92\le n\le 1e5,1\le m\le 5,1\le a_{i,j},w_i\le 1e92≤n≤1e5,1≤m≤5,1≤ai,j,wi≤1e9
思路
看到mmm很小,很容易向状压地方靠,假设aaa很小,那么这个题就很简单了,我们将每个数组状压成一个二进制,让后sosdpsosdpsosdp求一下子集最小值,让后遍历即可获得答案。
但是这个题aaa高达1e91e91e9,但是我们发现其最终答案是一对之间,那么我们将aaa随机映射到0−150-150−15之间的某个数,注意同一个数一定映射到相同数,不同数可能映射到相同数,我们发现这样操作后对于答案的两个数组他们都映射到不同数上的概率为0.01880.01880.0188,这也是答案正确的概率,虽然这个数很小,但是我们运行200200200次,期望概率就达到222以上了,基本可以认为是正确的。
复杂度P(250∗16∗(1<<16))P(250*16*(1<<16))P(250∗16∗(1<<16))
trick: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;
}