本文主要是介绍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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!