题解 赛
感觉和这题很像,但是分的时间少了没来的及细想
而且连\(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;
}