[CSP-S模拟测试]:赛(贪心+三分)
Posted wzc521
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CSP-S模拟测试]:赛(贪心+三分)相关的知识,希望对你有一定的参考价值。
题目描述
由于出题人思维枯竭所以想不出好玩的背景。
有$n$个物品,第$i$个物品的价格是$v_i$,有两个人,每个人都喜欢$n$个物品中的一些物品。
要求选出正好$m$个物品,满足选出的物品中至少有$k$个物品被第一个人喜欢,$k$个物品被第二个人喜欢。并求出最小的价格和。
输入格式
第一行三个数$n,m,k$。
第二行$n$个数,第$i$个数表示$v_i$。
第三行包含一个数$a$,表示第一个人喜欢的物品数。
第四行包含$a$个数,表示第一个人喜欢的物品是哪几个。
第五行包含一个数$b$,表示第二个人喜欢的物品数。
第六行包含$b$个数,表示第二个人喜欢的物品是哪几个。
输出格式
一个数表示答案。若不存在合法的方案则输出$-1$。
样例
样例输入:
4 3 2
3 2 2 1
2
1 2
2
1 3
样例输出:
7
数据范围与提示
对于测试点$1\\sim 4$:$n\\leqslant 20$。
对于测试点$5\\sim 10$:不存在一个物品被两个人喜欢。
对于测试点$11\\sim 15$:$n\\leqslant 2\\times 10^3$。
对于测试点$16\\sim 20$:无特殊限制。
对于所有的数据,$n\\leqslant 2\\times 10^5,m,k\\leqslant n,v_i\\leqslant 10^9$。
题解
这道题优秀的随机化可以拿到$95$分……
我们可以设两个人喜欢的物品交集个数为$r$,那么我们就可以贪心了。
发现答案满足单谷,于是我们可以三分。
其实三分也是存在漏洞的,因为一段的$r$可能对应一样的答案,但是显然随机数据没有卡。
时间复杂度:$\\Theta(n\\log k)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
int N,M,K,A,B;
int v[200001];
bool a[200001],b[200001];
int que[4][200001],top1,top2,top3,top4;
long long ans=1LL<<60;
bool cmp(int x,int y)return v[x]<v[y];
long long judge(int x)
long long res=0;
for(int i=1;i<=x;i++)res+=v[que[3][i]];
for(int i=1;i<=K-x;i++)res+=v[que[1][i]];res+=v[que[2][i]];
int lst=M-x-2*max(K-x,0);
int flag1=max(K-x,0)+1;
int flag2=max(K-x,0)+1;
int flag3=1;
while(lst)
if(v[que[1][flag1]]<=v[que[2][flag2]]&&v[que[1][flag1]]<=v[que[0][flag3]])
res+=v[que[1][flag1]];
flag1++;
else if(v[que[2][flag2]]<=v[que[1][flag1]]&&v[que[2][flag2]]<=v[que[0][flag3]])
res+=v[que[2][flag2]];
flag2++;
else
res+=v[que[0][flag3]];
flag3++;
lst--;
return res;
int main()
scanf("%d%d%d",&N,&M,&K);
for(int i=1;i<=N;i++)scanf("%d",&v[i]);
scanf("%d",&A);
for(int i=1;i<=A;i++)
int x;
scanf("%d",&x);
a[x]=1;
scanf("%d",&B);
for(int i=1;i<=B;i++)
int x;
scanf("%d",&x);
b[x]=1;
for(int i=1;i<=N;i++)
if(!a[i]&&!b[i])que[0][++top1]=i;
if( a[i]&&!b[i])que[1][++top2]=i;
if(!a[i]&& b[i])que[2][++top3]=i;
if( a[i]&& b[i])que[3][++top4]=i;
if(top2+top4<K||top3+top4<K||top4<max(2*K-M,0)||M<K||min(top4,K)+2*max(K-top4,0)>M)puts("-1");return 0;
sort(que[0]+1,que[0]+top1+1,cmp);
sort(que[1]+1,que[1]+top2+1,cmp);
sort(que[2]+1,que[2]+top3+1,cmp);
sort(que[3]+1,que[3]+top4+1,cmp);
v[0]=0x3f3f3f3f;
int lft=max(K-min(top2,top3),max(2*K-M,0));
int rht=min(K,top4);
while(rht-lft>2)
int midl=lft+(rht-lft)/3;
int midr=rht-(rht-lft)/3;
if(judge(midl)<judge(midr))rht=midr;
else lft=midl;
ans=min(ans,judge(lft));
ans=min(ans,judge(lft+1));
ans=min(ans,judge(rht));
if(ans==(1LL<<60))puts("-1");
else printf("%lld",ans);
return 0;
rp++
以上是关于[CSP-S模拟测试]:赛(贪心+三分)的主要内容,如果未能解决你的问题,请参考以下文章