CF 773 (Div. 1) D. Two Arrays 双指针 容斥
共有\(n\)个向量,找两个代价和最小且不存在任意元素相同的两个向量。
本题特殊之处在于每个向量元素个数之多为\(5\)。
本题一个妙手是转换成双指针模型,按价值排序后,对于当前可行区间\(l,r\)随着右端点的增大,左端点只有变小才有可能更新答案。
接下来考虑如何判断\(1-l\)之中如何存在向量与\(a_r\)不冲突。
考虑容斥,对于\(a_r\)的\(2^m\)的子集查询在其中出现次数\(c\),大小为\(w\),贡献为\(c(-1)^w\)。由二项式定理可知若存在不冲突这个值应该不为0。
直接hash map会超时。
这里有两种策略一种是双hash链表处理。一种是map标号,把向量从小到大排序后开5*n个map不断的存下去一个向量链并标号。
由此复杂度降到了\(n2^m+nlogn\)。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x)
#define putl_(x) printf("%lld ",x)
#define get(x) x=read()
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;i+=1)
#define fep(n,p,i) for(int i=n;i>=p;--i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define ui unsigned
#define sq sqrt
#define x(w) t[w].x
#define r(w) t[w].r
#define id(w) t[w].id
#define R(w) s[w].r
#define sum(w) t[w].sum
#define sc(A) scanf("%d",&A)
#define scl(A) scanf("%lld",&A)
#define scs(A) scanf("%s",A);
#define put(A) printf("%d\n",A)
#define min(x,y) (x>=y?y:x)
#define max(x,y) (x>=y?x:y)
#define sub(x,y) (x-y<0?x-y+mod:x-y)
#define uint unsigned int
#define mod 998244353
#define mod1 1000000007
#define zz p<<1
#define yy p<<1|1
using namespace std;
const int MAXN=100010,G=3,mol=10000007;
int n,m;
int a[MAXN][6];
int w[MAXN],p[MAXN];
int cmp(int a,int b){return w[a]<w[b];}
map<pair<int,int>,int>H;
int lin[mol],nex[mol*2],ver[mol*2],e[mol*2],len;
void add(int x,int y,int z)
{
ver[++len]=y;
nex[len]=lin[x];
e[len]=z;
lin[x]=len;
}
int find(int x,int y,int z)
{
go(x)
{
if(ver[i]==y)
{
e[i]+=z;
return e[i];
}
}
return -1;
}
void add(int d,int x,int v,int w,int w1)
{
if(d==m+1)
{
if(find(w,w1,v)!=-1)return;
add(w,w1,v);
return;
}
add(d+1,x,v,w,w1);
add(d+1,x,v,((ll)w*mod%mol+a[x][d])%mol,((ll)w1*13331%mod1+a[x][d])%mod1);
}
int cnt=0;
void dfs(int d,int x,int c,int w,int w1)
{
if(d==m+1)
{
int ww=find(w,w1,0);
ww=ww==-1?0:ww;
cnt+=(c&1)?-ww:ww;
return;
}
dfs(d+1,x,c,w,w1);
dfs(d+1,x,c+1,((ll)w*mod%mol+a[x][d])%mol,((ll)w1*13331%mod1+a[x][d])%mod1);
}
int ask(int x)
{
cnt=0;
dfs(1,x,0,0,0);
return cnt>0;
}
int b[MAXN][6];
int main()
{
int N;
sc(N);sc(m);
int ans=2000000010;
rep(1,N,i)
{
rep(1,m,j)sc(b[i][j]);
sort(b[i]+1,b[i]+1+m);
int flag=0,cost;
rep(2,m,j)if(b[i][j]==b[i][j-1])flag=1;
sc(cost);
if(!flag)
{
++n;
rep(1,m,j)a[n][j]=b[i][j];
w[n]=cost;p[n]=n;
}
}
//cout<<n<<endl;
sort(p+1,p+1+n,cmp);
int L=0;
rep(1,n,i)
{
if(w[p[i]]>ans)break;
if(!L)add(0,p[i],1,0,0);
if(i!=1)
{
if(L==0)
{
if(ask(p[i]))
{
L=i-1,add(0,p[L],-1,0,0);
add(0,p[i],-1,0,0);
}
}
}
while(L>=2&&ask(p[i]))
{
--L;
add(0,p[L],-1,0,0);
}
//cout<<i<<' '<<L<<endl;
if(L)ans=min(ans,w[p[i]]+w[p[L]]);
}
put(ans==2000000010?-1:ans);
return 0;
}