Kickstart Round D 2018 B题 Paragliding

Posted 同学少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kickstart Round D 2018 B题 Paragliding相关的知识,希望对你有一定的参考价值。

题目大意:有N个塔,水平坐标为 p[i], 高度为 h[i], 每个塔的水平坐标各不相同。 有K个气球,每个气球可看做一个点,坐标为x[i], y[i]。一个人可以爬到每个塔的任意高度位置,然后在该位置可以向左右45度滑行,滑行的轨迹是直线。如果在途中遇到气球,则可获得该气球,如果气球和塔相重叠,也认为可获得气球,要求一共可以获得多少个气球。

解题关键点:

1. 如果从一个塔( p[j], h[j]  )向下滑行可以获得某个气球(x[i], y[i]), 则满足 abs(x[i] - p[j] ) + y[i] <= h[j]

2. 如果一个塔 i 和另外一个塔 j 满足 abs(p[i] - p[j]) + h[i] <= h[j], 则第i个塔是多余的,因为任意从第i个塔滑行获得的气球,都可以通过从第j个塔滑行获得。

解题方法:

1. 小数据: 将每个气球和所有的塔进行关键点1条件比较,如果满足,则该气球可获得。

2. 大数据: 对于每个气球,如果我们能找到能它最近的塔,只判断是否能从离它最近的塔上获得就好了。但是存在这样一个问题,如果从离它最近的塔上不能获得,也许存在离它较远位置的塔,从这些塔上获得气球。这样的话,还得依次遍历所有的塔。为了达到最初的想法,考虑关键点2, 如果我们把所有多余的塔去掉,那么就可以只判断是否能从离它最近的塔上获得就可以了。为什么? 假设某个气球坐标为(x, y) , 离它最近的右边的塔为(p1, h1),从该塔不能获得气球,则满足 p1 - x + y > h1, 该式子等于 -p1 + x - y + h1 < 0, 又假设存在离该气球更远的塔(p2, h2 )  p2 >p1, 从该塔上可以获得气球,则满足 p2 - x + y <= h2, 将这个式子和前面的式子相加得到  p2 - p1 + h1 <= h2,正好关键点2中的条件,也就是说离它最近的那个塔是多余的。 所以,我们把所有多余的塔去掉之后,就可以找到离某个气球最近的塔,找的过程可以将所有的塔从小到大排好序,再使用二分搜索进行查找。

代码:

#include <iostream>
#include <iostream>
#include <string.h>
#include <iomanip>
#include <algorithm>
#include <stdio.h>
#include <map>
#include <set>
#include <queue>
#include <stack>
using namespace std;
typedef long long ll;

const int maxn = 100010;
ll p[maxn], h[maxn], x[maxn], y[maxn];
ll relevantT[maxn];
ll towerSorted[maxn];//排好序的塔
map<ll, int> valueAndID; //塔的位置和索引
ll A[5], B[5], C[5], M[5];
int T, N, K;

int getRelation(int i, int j)//第i个塔, 第j个塔 i > j

    if(h[j] >= p[i] - p[j] + h[i]) //第i个塔是多余的
        return 1;
    if(h[i] >= p[i] - p[j] + h[j]) //第j个塔是多余的
        return 2;
    return 3;


bool ok(int i, int j)//第i个气球,第j个塔

    if(abs(x[i] - p[j]) + y[i] <= h[j])
        return true;
    return false;



int getRelevantTowers()

    for(int i = 1; i <= N; i++)
    
        towerSorted[i] = p[i];
        valueAndID[p[i]] = i;
    
    sort(towerSorted + 1, towerSorted + 1 + N);

    stack<ll> st;
    for(int i = 1; i <= N; i++)
    
        if(st.empty())
        
            st.push(towerSorted[i]);
            continue;
        

        int relation = getRelation(valueAndID[towerSorted[i]], valueAndID[st.top()]);

        if(relation == 1)//多余的
            continue;
        if(relation == 2)//栈顶的塔是多余的
        
            st.pop();
            while(!st.empty() && getRelation(valueAndID[towerSorted[i]], valueAndID[st.top()]) == 2)
            
                st.pop();
            
        
        st.push(towerSorted[i]);
    
	
    int len = st.size();
    int tp = len;
    while(!st.empty())
    
        relevantT[tp--] = st.top();
        st.pop();
    
	
    return len;


int main()

    freopen("B-large-practice.in", "r", stdin);
    freopen("out2.txt", "w", stdout);
    cin >> T;
    for(int cas = 1; cas <= T; cas++)
    
        valueAndID.clear();
        cin >> N >> K;

        cin >> p[1] >> p[2] >> A[1] >> B[1] >> C[1] >> M[1];
        for(int i = 3; i <= N; i++)
            p[i] = (A[1] * p[i - 1] + B[1] * p[i - 2] + C[1]) % M[1] + 1;

        cin >> h[1] >> h[2] >> A[2] >> B[2] >> C[2] >> M[2];
        for(int i = 3; i <= N; i++)
            h[i] = (A[2] * h[i - 1] + B[2] * h[i - 2] + C[2]) % M[2] + 1;

        cin >> x[1] >> x[2] >> A[3] >> B[3] >> C[3] >> M[3];
        for(int i = 3; i <= K; i++)
            x[i] = (A[3] * x[i - 1] + B[3] * x[i - 2] + C[3]) % M[3] + 1;

        cin >> y[1] >> y[2] >> A[4] >> B[4] >> C[4] >> M[4];
        for(int i = 3; i <= K; i++)
            y[i] = (A[4] * y[i - 1] + B[4] * y[i - 2] + C[4]) % M[4] + 1;

        int len = getRelevantTowers();
        int ans = 0;

        for(int i = 1; i <= K; i++)
        
            int L = lower_bound(relevantT + 1, relevantT + 1 + len, x[i]) - relevantT;

            //和塔重叠
            if(x[i] == relevantT[L])
            
                if(ok(i, valueAndID[relevantT[L]]))
                    ans++;
                continue;
            

            //该气球在最左边
            if(L == 1)
            
                if(ok(i, valueAndID[relevantT[L]]))
                    ans++;
                continue;
            
			//该气球在最右边
            if(L > len)
            
                if(ok(i, valueAndID[relevantT[len]]))
                    ans++;
                continue;
            

            //该气球处在两个塔之间
            int LL = L - 1;
            int RR = L;
            if(ok(i, valueAndID[relevantT[LL]]))
            
                ans++;
                continue;
            
            if(ok(i, valueAndID[relevantT[RR]]))
                ans++;
        
        cout << "Case #" << cas <<": " << ans <<endl;
    
    return 0;

 

以上是关于Kickstart Round D 2018 B题 Paragliding的主要内容,如果未能解决你的问题,请参考以下文章

Kickstart2018 Round (Practice ~ H)

kickstart_Round C 2020

Codeforces Round #624 (Div. 3) D 题

Codeforces Round #451 (Div. 2)A,B,C,D,EC题:模拟 D题:尺取+贪心 E题:思维+优先队列维护最值

Google Kickstart 2020 Round A 分配问题

kickstart 谷歌 D 2020 年 7 月 12 日 13: 00 - 16: 00