题目:
题目描述
兽族太子称帝了。听到这个消息后,人族的最高统治者GM感觉受到了威胁,并很快宣布自己是人皇!由于这片土地上不可能有两位国王,他们决定一劳永逸地解决权力争端。 GM将与王国最强大的N个勇士从1到N编号,去拜访兽族的城堡。 在城堡大厅,N个最强的兽人坐成一圈迎接他们,兽人按顺时针从1到N编号。 进入城堡后,兽王给了GM的每一个勇士一个号码Ai,这是他们将要对抗的兽人的编号。不幸的是,他没有确定每个勇士应该得到一个唯一的对手,很快就会发生一场可怕的战斗。 他们决定以下列方式解决问题: ●GM将按照他选择的顺序将勇士一个接一个地送到大厅。下一个勇士只有在他前面的勇士坐下之后才能进入大厅。 ● 编号为k的勇士将首先接近标记为Ak的兽人。如果兽人旁边没有勇士,他会坐在那里。否则,他将继续顺时针地绕着兽人的圈子走,直到找到一个身边没有勇士的兽人。 现在,由此产生的N对勇士和兽人参加了摔跤比赛,强者总是获胜。 GM为此次活动做好了充分的准备。他研究了所有的勇士和兽人,并确定了每个战士的实力。现在他想按照一种顺序将勇士送到大厅,在他们坐下之后,他们将为他带来最大的胜利。 帮助他计算勇士可以达到的最高胜利次数!
输入格式
第一行输入包含整数N (1≤N≤5∗1e5)表示兽人和勇士的数量。 第二行输入包含N个整数Ai (1≤Ai≤N)。表示兽王为第i个勇士选择的对手。 第三行输入包含N个整数Pi (1≤Pi≤1e9)。表示第i个兽人的实力。 第四行输入包含N个整数Vi (1≤Vi≤1e9)。表示第i个勇士的实力。 输入保证这2N个实力值互不相同。
输出格式
一个整数。表示人类可以达到的最大胜利次数。
样例
样例输入
3
2 3 3
4 1 10
2 7 3
样例输出
2
分析&题解:
思路
这道题首先要弄清楚它的题意
样例是这样的:
这里二号魔兽的战斗值应该为1,写错了....
二号魔兽有一个人,战斗值为2,三号魔兽对应了两个人,战斗力为3,7
那么最好的情况是3对10,7对4,可以赢2场
那么其实这道题的贪心就出来了:
如果一个魔兽对应的有多个人,且能力值都比他们高的话,就选一个人能力值最小的当炮灰
其它的人顺时针转就可以了
否则就把这群人中能力值刚好大于这个魔兽的人找出来(题目保证每个人或魔兽的能力值不等),让他与其匹配,其他的人继续移
那现在就有一个问题,从哪一个点开始可以保证保证一次性做完
拿样例说,如果从第一个魔兽开始,那么第一个魔兽就匹配不了
由于这是一个环,我们要选择破环成链
定义Ri表示前i个位置所有人的个数,这里开头从1开始
定义Pi=Ri-i,表示前i个位置一一匹配后还剩多少个人
那么找到最小的Pi的i,那么从i+1开始就可以一次性做完
为什么呢?
很简单,因为Pi最小肯定是小于等于0的(由于Pn = 0 前缀和可知了,那么Pi<=0)
如果Pi =0 , 那么1-i之间是可以通过自己移动来填满位置,那么反推也可以得i+1-n也是可以内部移动填满的
如果Pi = 0,那么i+1-n的点一定是有点要跑到1-i来的,而由于1-i的人类本身就不够,那么就更不可能移到i+1-n去了
做法
其实是要用到set与vector,由于set自动排序,且可以直接删除,就会变得很简单
#include <iostream>//亲测用数组模拟set全部超时
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;
const int MAXN = 1e5 * 5 + 4;
int n ;
int a[MAXN] , p[MAXN] , r[MAXN];
int sum[MAXN];
set<int>se;
vector<int>G[MAXN];
void find_( int start ){
int ans = 0;
int j = 1, i ;
for( i = start ; j <= n; j ++ ){
for( int k = 0; k < G[i].size() ; k ++ )
se.insert(G[i][k]);//第i个兽打的人有从i-1移过来的和本身就要与它对决的
set<int>::iterator is = se.lower_bound( p[i] );//后面就是贪心了
if( is == se.end() ){
se.erase( se.begin() );
}
else{
se.erase( is );
ans ++;
}
if( i == n ) i = 1;
else
i ++;
}
printf( "%d" , ans );
}
int main(){
scanf("%d" , &n );
for(int i = 1 ; i <= n ;i ++ )
scanf("%d" , &a[i] );
for( int i = 1 ; i <= n ; i ++)
scanf( "%d" , &p[i] );
for(int i = 1; i <= n ; i ++ ){
scanf( "%d" , &r[i] );
sum[a[i]] ++;//预处理r[]数组
G[a[i]].push_back( r[i] );//第i个兽所对的人
}
int minn = 0x7f7f7f7f, m = 0;
for(int i = 1 ; i <= n ; i ++ ){
sum[i] += sum[i-1];
if( sum[i] - i < minn )
minn = sum[i] - i , m = i;//找最小的Pi
}
if( m + 1 > n ) m = 1;
else m ++;
find_( m );
return 0;
}