CF 546 div.2 D. Nastya Is Buying Lunch(思维+贪心)

27 篇文章 0 订阅

为数不多的纯靠自己想出来的DIV2 D题
题意是 给出一个排好的队列,以及m个可交换的操作(u,v) :当u在v的前面时,u和v可直接交换位置
问最后一个人(编号Pn)最多可以向前几个位置。
在正式解题前想了很多没用的东西,比如多个数可以跟Pn怎么交换时用什么顺序才可以把我们要换的目标换过去,经过一点思考后浅显的得出了一个结论:后面能交换的就先交换,如果先交换后面的,搞不好能按这个顺序一路把目标人物换过去。于是按u的位置大小来排序,u在后面的先操作,然后直接贡献了一发。

正经思考:
容易想到,Pn能往前的位置的个数最多就是 所有交换操作中,能和Pn交换的操作个数。而要这样的交换操作要能实现,首先这个点得先能够走到Pn的面前,也就是说这个点必须能跟Pn之间夹着的人都能交换,而其他位置的人能否交换是无关紧要的(我一直觉得有影响,实际上按这个思路细想没有影响,要处理的是能和Pn交换的人)。可以用位置相减得到操作能达成要交换的个数,那么只要计算一下,比较一下是否交换次数大于等于需要的交换次数,就可以判断能不能完成这个交换操作,而完成一个,位置就可以加1。贪心的思想在于,多个可以跟Pn交换的人,前面的人,计算需要交换的次数时会把后面可以跟pn交换的人也算进去,如果我们按顺序一步一步把Pn往前移,他们的实际距离其实是中间夹着的那些不能和Pn交换的人的个数,因为即使两个都可以跟Pn交换的人之间不能交换,我也能通过先把后面的人换到Pn后面去而使得前面那个人不必经过后面那个人就能和Pn交换(这里还有一个坑点,如果后面那个人不能完成交换,那么前面的人算距离时必须把这个人算进去,否则会WA在69)。

语言能力有限:看代码了

#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int n,m,q[maxn],pos[maxn],num[maxn];
vector<int> g;
struct ss{
 	int u,v;
}a[maxn];
bool cmp(int a,int b){
 	return pos[a]>pos[b];
}
int main(){
 	scanf("%d%d",&n,&m);
 	for(int i = 1; i <= n; i++){
 		scanf("%d",&q[i]);
  		pos[q[i]]=i;
 	}
 	for(int i = 1; i <= m; i++){
  		scanf("%d%d",&a[i].u,&a[i].v);
  		if(a[i].v==q[n])
   			g.push_back(a[i].u);
 	}
 	sort(g.begin(),g.end(),cmp);
 	for(int i = 1; i <= m; i++){
  		int u=a[i].u,v=a[i].v;
  		if(pos[v]>pos[u]) num[u]++;
 	}
 	int ans=0;
 	for(int i = 0; i < g.size(); i++){
  		if(num[g[i]]>=(pos[q[n]]-pos[g[i]]-ans))
   			ans++;
 	}
 	printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值