题解 赛

传送门

感觉和这题很像,但是分的时间少了没来的及细想
而且连\(n^2\)暴力都写挂了……分配的时间太少了没来得及跑对拍

第一思路是按喜欢的情况分为四类,然后枚举两人都喜欢的选多少个
这样直接写就是\(n^2logn\)
这类问题的处理方法就是考虑如何能每次不重新构建情况,而是从上一次的最优情况转移过来,
而且好像一般要倒序枚举以避免枚举到选\(i\)个的时候,其它集合不好从\(i-1\)继承
然后要保证当前状态一直合法,所以先取到一个合法情况
both每次少选一个,alike,blike补满k个(次数不够用分给other的次数补)
就可以了
写细节题不要心急……慢慢写,把边界判断写足,assert写足,就好调得多了

关于最优决策一定会被枚举到的证明……
都喜欢的会被枚举到
选定的一直是\(m\)
每次在补够\(m\)个的前提下一直在三个集合中取最小
每次都相当于维护出了在满足两人都选够\(k\)个的情况下,从剩下的三个集合中不断取小直到够\(m\)个的状态
所以和\(n^2\)的解法是一样的
然而更加珂学的证明先咕了

Code:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f
#define N 200010
#define ll long long 
#define ld long double
#define usd unsigned
#define ull unsigned long long
#define int long long 

#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m, k;
int val[N], alike[N], atop, blike[N], btop;
bool vis1[N], vis2[N];

namespace force{
	ll ans=INF;
	void solve() {
		int lim=1<<n;
		ll sum;
		for (int s=1,cnt,s2,ka,kb; s<lim; ++s) {
			s2=s; cnt=0; sum=0; ka=0; kb=0;
			while (s2) {++cnt; s2&=s2-1;}
			if (cnt!=m) goto jump;
			for (int j=0; j<n; ++j) if (s&(1<<j)) {
				sum+=val[j+1];
				if (sum>ans) goto jump;
				if (vis1[j+1]) ++ka;
				if (vis2[j+1]) ++kb;
			}
			if (ka>=k && kb>=k) ans=min(ans, sum);
			jump: ;
		}
		printf("%lld\n", ans==INF?-1:ans);
		exit(0);
	}
}

namespace task1{
	priority_queue< int, vector<int>, greater<int> > qa, qb, qc;
	ll ans;
	void solve() {
		if (k*2>m) {puts("-1"); exit(0);}
		for (int i=1; i<=atop; ++i) qa.push(val[alike[i]]);
		for (int i=1; i<=btop; ++i) qb.push(val[blike[i]]);
		for (int i=1; i<=n; ++i) if (!vis1[i]&&!vis2[i]) qc.push(val[i]); //, cout<<"push "<<val[i]<<endl;
		for (int i=1; i<=k; ++i) {ans+=qa.top(); qa.pop();}
		//cout<<"ans: "<<ans<<endl;
		for (int i=1; i<=k; ++i) {ans+=qb.top(); qb.pop();}
		//cout<<"ans: "<<ans<<endl;
		while (qa.size()) qc.push(qa.top()), qa.pop();
		while (qb.size()) qc.push(qb.top()), qb.pop();
		for (int i=1; i<=m-k*2; ++i) {ans+=qc.top(); qc.pop();}
		//cout<<"ans: "<<ans<<endl;
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task2{
	//priority_queue< int, vector<int>, greater<int> > both, other;
	//priority_queue< int, vector<int>, less<int> > qa, qb;
	priority_queue< int, vector<int>, greater<int> > q;
	ll ans=INF;
	int tot, both[N], other[N], osiz;
	void solve() {
		tot=0; btop=0; atop=0; osiz=0;
		for (int i=1; i<=n; ++i) {
			if (vis1[i]&&vis2[i]) both[++tot]=val[i];
			else if (vis1[i]) {
				alike[++atop]=val[i];
			}
			else if (vis2[i]) {
				blike[++btop]=val[i];
			}
			else other[++osiz]=val[i];
		}
		sort(both+1, both+tot+1);
		sort(alike+1, alike+atop+1);
		sort(blike+1, blike+btop+1);
		sort(other+1, other+osiz+1);
		#if 0
		cout<<"both: "; for (int i=1; i<=tot; ++i) cout<<both[i]<<' '; cout<<endl;
		cout<<"alike: "; for (int i=1; i<=atop; ++i) cout<<alike[i]<<' '; cout<<endl;
		cout<<"blike: "; for (int i=1; i<=btop; ++i) cout<<blike[i]<<' '; cout<<endl;
		cout<<"other: "; for (int i=1; i<=osiz; ++i) cout<<other[i]<<' '; cout<<endl;
		#endif
		//cout<<tot<<' '<<atop<<' '<<btop<<' '<<osiz<<endl;
		ll bothsum=0, sum, cnt;
		for (int i=0,pos; i<=min(tot, m); ++i) {
			cnt=i;
			if (i>0) bothsum+=both[i], sum=bothsum;
			else sum=0;
			if (i<k && k-i>min(atop, btop)) goto jump;
			while (q.size()) q.pop();
			//cout<<"sum: "<<sum<<endl;
			pos=1; for (int j=i+1; j<=k&&pos<=atop; ++j) sum+=alike[pos++], ++cnt;
			while (pos<=atop) q.push(alike[pos++]); //, cout<<"push "<<alike[pos-1]<<endl;
			//cout<<"sum: "<<sum<<endl;
			pos=1; for (int j=i+1; j<=k&&pos<=btop; ++j) sum+=blike[pos++], ++cnt;
			while (pos<=btop) q.push(blike[pos++]);
			//cout<<"sum: "<<sum<<endl;
			pos=1; while (pos<=osiz) q.push(other[pos++]);
			while (cnt<m && q.size()) sum+=q.top(), q.pop(), ++cnt;
			//cout<<"sum: "<<sum<<endl;
			if (cnt<m || cnt>m) goto jump;
			ans = min(ans, sum);
			//cout<<"upd "<<i<<' '<<sum<<endl;
			jump: ;
		}
		printf("%lld\n", ans==INF?-1:ans);
		exit(0);
	}
}

namespace task{
	int tot, both[N], other[N], osiz, suma[N], sumb[N];
	void solve() {
		tot=0; btop=0; atop=0; osiz=0;
		for (int i=1; i<=n; ++i) {
			if (vis1[i]&&vis2[i]) both[++tot]=val[i];
			else if (vis1[i]) alike[++atop]=val[i];
			else if (vis2[i]) blike[++btop]=val[i];
			else other[++osiz]=val[i];
		}
		sort(both+1, both+tot+1);
		sort(alike+1, alike+atop+1);
		sort(blike+1, blike+btop+1);
		sort(other+1, other+osiz+1);
		
		ll sum=0, ans=INF;
		int pboth=min(tot, m), pa=1, pb=1, po=1, ka=0, kb=0, cnt=0, minn;
		for (int i=1; i<=pboth; ++i) sum+=both[i], ++ka, ++kb, ++cnt;
		while (ka<k && pa<=atop) sum+=alike[pa++], ++ka, ++cnt;
		if (ka<k) {puts("-1"); exit(0);}
		while (kb<k && pb<=btop) sum+=blike[pb++], ++kb, ++cnt;
		if (kb<k) {puts("-1"); exit(0);}
		while (cnt<m) {
			minn = min( min( pa<=atop?alike[pa]:INF, pb<=btop?blike[pb]:INF), po<=osiz?other[po]:INF );
			if (pa<=atop && minn==alike[pa]) sum+=alike[pa++], ++ka, ++cnt;
			else if (pb<=btop && minn==blike[pb]) sum+=blike[pb++], ++kb, ++cnt;
			else if (po<=osiz && minn==other[po]) sum+=other[po++], ++cnt;
			else break;
		}
		//cout<<"cnt: "<<cnt<<endl;
		if (cnt<m || cnt>m) {puts("-1"); exit(0);}
		ans=min(ans, sum);
		//cout<<"begin: "<<sum<<endl;
		for (int i=min(tot, m),dlt; i; --i) {
			sum-=both[i]; --ka; --kb; dlt=-1;
			while (ka<k && pa<=atop) sum+=alike[pa++], ++ka, ++dlt;
			if (ka<k) break;
			while (kb<k && pb<=btop) sum+=blike[pb++], ++kb, ++dlt;
			if (kb<k) break;
			while (po && dlt>0) sum-=other[--po], --dlt;
			if (!po) break;
			if (dlt<0) {
				minn = min( min( pa<=atop?alike[pa]:INF, pb<=btop?blike[pb]:INF), po<=osiz?other[po]:INF );
				if (pa<=atop && minn==alike[pa]) sum+=alike[pa++], ++ka;
				else if (pb<=btop && minn==blike[pb]) sum+=blike[pb++], ++kb;
				else if (po<=osiz && minn==other[po]) sum+=other[po++];
				else break;
			}
			//cout<<"upd: "<<i<<' '<<sum<<endl;
			ans=min(ans, sum);
		}
		printf("%lld\n", ans);
		exit(0);
	}
}

signed main()
{
	#ifdef DEBUG
	freopen("1.in", "r", stdin);
	#endif
	int a, b;
	bool nosame=1;
	
	n=read(); m=read(); k=read();
	if (!m || m>n) {puts("-1"); return 0;}
	for (int i=1; i<=n; ++i) val[i]=read();
	a=read();
	if (a<k) {puts("-1"); return 0;}
	for (int i=1,t; i<=a; ++i) {
		t=read(), vis1[t]=1;
		alike[i]=t;
	}
	b=read();
	if (b<k) {puts("-1"); return 0;}
	for (int i=1,t; i<=b; ++i) {
		t=read(), vis2[t]=1;
		blike[i]=t;
		if (vis1[t]) nosame=0;
	}
	atop=a; btop=b;
	//if (nosame) task1::solve();
	//else if (n<=22) force::solve();
	//else task2::solve();
	task::solve();

	return 0;
}
posted @ 2021-07-23 09:35  Administrator-09  阅读(11)  评论(0编辑  收藏  举报