[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++

原文地址:https://www.cnblogs.com/wzc521/p/11615892.html

时间: 2024-11-09 09:37:20

[CSP-S模拟测试]:赛(贪心+三分)的相关文章

2018冬令营模拟测试赛(三)

2018冬令营模拟测试赛(三) [Problem A]摧毁图状树 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 这题没想到贪心 QwQ,那就没戏了-- 贪心就是每次选择一个最深的且没有被覆盖的点向上覆盖 \(k\) 层,因为这个"最深的没有被覆盖的点"不可能再有其它点引出的链覆盖它了,而它又

2018冬令营模拟测试赛(十九)

2018冬令营模拟测试赛(十九) [Problem A]小Y 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 目前未知. 这题目前就能做到 \(O(n \sqrt{M} \log n)\),其中 \(M\) 是逆序对数,然而会被卡 \(T\):当然这题暴力可以拿到和左边那个算法一样的分数,只要暴力加一个剪枝:当左

2018冬令营模拟测试赛(五)

2018冬令营模拟测试赛(五) [Problem A][UOJ#154]列队 试题描述 picks 博士通过实验成功地得到了排列 \(A\),并根据这个回到了正确的过去.他在金星凌日之前顺利地与丘比签订了契约,成为了一名马猴烧酒. picks 博士可以使用魔法召唤很多很多的猴子与他一起战斗,但是当猴子的数目 \(n\) 太大的时候,训练猴子就变成了一个繁重的任务. 历经千辛万苦,猴子们终于学会了按照顺序排成一排.为了进一步训练,picks 博士打算设定一系列的指令,每一条指令 \(i\) 的效果

2018冬令营模拟测试赛(十七)

2018冬令营模拟测试赛(十七) [Problem A]Tree 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 这个数据范围肯定是树上背包了. 令 \(f(i, j, k)\) 表示子树 \(i\) 中选择了 \(j\) 个节点,路径与根的连接情况为 \(k\),具体地: \(k = 0\) 时,路径的两个端点

[CSP-S模拟测试]:C(三分+贪心)

题目传送门(内部题46) 输入格式 第一行$3$个整数$n,m,t$.第二行$n$个整数,表示$P_i$.接下来$m$行每行两个整数,表示$L_i,R_i$. 输出格式 一行一个整数表示答案. 样例 样例输入: 3 3 26 2 51 12 23 3 样例输出: 11 数据范围与提示 样例解释: 最优方案为使用$2$次特殊加热器,$4$次$1$号加热器,$3$次$3$号加热器. 数据范围: 对于前$20\%$的数据:$t\geqslant n$对于另$30\%$的数据:$P_i\leqslant

2018.8.6 Noip2018模拟测试赛(十九)

日期: 八月六号  总分: 300分  难度: 提高 ~ 省选    得分: 10分(MMP) 题目目录: T1:Tree T2:异或运算 T3:Tree Restoring 赛后反思: Emmmmmmm…… 一直在打第一题…… 结果考完才发现dp少了一种情况…… 除此之外,我无话可说…… Emmmmmm…… 题解: T1:Tree 树形背包dp,设$f[i][j][k(0/1/2)]$为$i$的子树中,选$j$条边,0:从$i$出发,到$i$结束/1:从$i$出发,到$i$的某个后代结束/2:

测试赛D - The War(有控制范围的贪心)

D - The War Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Description A war had broken out because a sheep from your kingdom ate some grasses which belong to your neighboring kingdom. The counselor of your k

[考试反思]0929csp-s模拟测试55:沦陷

菜得过分. 面对T1的大板子不知所措,然后T2的贪心不小心把排序语句删了... T1这种大模板啊...其实我是觉得我能打出来的,然后先用一个小时码了一个2k. 然后做T2想贪心就出来了.十分钟码完T3暴力之后回T1打对拍瞬间爆炸. 于是又重新打了一个2k,WA0.对拍发现. 然后考试就没几分钟了交暴力走了. 不要打完就跑,记得早点对拍改进思路. T1: 的确是挺裸的线段树.离散化或者权值线段树都可以. 但是考场上两个都打出来都死了. 最后用离散化A的. 1 #include<cstdio> 2

【2016北京集训测试赛(八)】 crash的数列

Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多点数列套着来加速转移呢? 但是发现好像太多数列套起来是可以烦死人的...... 我们就采用嵌套两次吧,记原数列为A,第一层嵌套为B,第二层嵌套为C. 我们其实可以发现一些规律,对于Ci,它对应了B中i的个数:对于Bi,它对应了A中i的个数. 稍加处理即可,我们一边计算一边模拟数列的运算,同时可以计算