Dota2 Pro Circuit 贪心-模拟

题意 :

  • n个队伍参加两轮比赛,给第一轮结束后每个队伍的分数,以及第二轮第i名可以获得的分数。
  • 求所有队伍的最高名次和最低名次(同分数名次并列)。

思路 :

  • 最高排名(让它下面的人最多),将它本身加上最大的b分,总分记为sc,剩余的a中从小到大枚举,让它们尽可能拿走最大的b分且总分小于等于sc分,到b中分数已经被枚举到了最后一个的时候就break了,a中剩下的个数就是排名在这个对象上面的了。
  • 最低排名(让它上面的人最多),将它本身加上最小的b分,总分记为sc,剩余的a中从大到小枚举,如果本身就比sc还大,说明加什么都会比sc大,直接让这个对象上面的人数 ++ 即可。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;

const int N  = 5e3 + 10;

ll a[N], b[N], r[N];

bool cmp1(int x, int y)
{
    return a[x] > a[y];
}
bool cmp2(ll x, ll y)
{
    return x > y;
}

int main()
{
    IOS;
    
    int _; cin >> _;
    
    while (_ -- )
    {
        int n;
        cin >> n;
        
        for (int i = 1; i <= n; i ++ ) cin >> a[i];
        for (int i = 1; i <= n; i ++ ) cin >> b[i];
        for (int i = 1; i <= n; i ++ ) r[i] = i;
        
        sort(r + 1, r + n + 1, cmp1);       // r中元素是将a数组元素从高到低排序后在a中的序号,即r[1]是a数组中元素最大值的下标
        sort(b + 1, b + n + 1, cmp2);       // b中元素从大到小
        
        for (int i = 1; i <= n; i ++ )
        {
            int hi = 0, lo = 0;
            
            // 最高排名
            ll sc = a[i] + b[1], k = 2;    // 本身给予最高分
            for (int j = n; j >= 1; j -- )      // a中得分从低到高枚举
            {
                ll jj = r[j];       // j == n时,jj是a数组中最小元素的下标
                if (jj == i) continue;
                while (a[jj] + b[k] > sc && k <= n) ++ k ;     // 找使得总得分小于等于sc的b中分数
                if (k <= n) ++ hi ;     // 找得到就 ++ ,使hi尽可能多,即在最高排名下,使得总得分小于等于sc的尽可能多
                ++ k ;
                if (k > n) break;
            }
            hi = n - hi;        // 剩下的分都比它高
            
            
            // 最低排名
            sc = a[i] + b[n], k = n - 1;
            for (int j = 1; j <= n; j ++ )
            {
                ll jj = r[j];
                if (jj == i) continue;
                if (a[jj] > sc)
                {
                    ++ lo ;
                    continue;
                }
                
                while (a[jj] + b[k] <= sc && k >= 1) -- k ;     // 找使得总得分大于sc的
                if (k < 1) break;
                ++ lo ;
                -- k ;
            }
            
            cout << hi << " " << lo + 1 << endl;
        }
        
    }
    
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值