魔兽世界(贪心)

题目:

题目描述

兽族太子称帝了。听到这个消息后,人族的最高统治者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;
}
发布了68 篇原创文章 · 获赞 7 · 访问量 3857

猜你喜欢

转载自blog.csdn.net/weixin_43823476/article/details/95196830