Security Check
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 239 Accepted Submission(s): 96
Problem Description
In airport of Bytetown, there are two long queues waiting for security check. Checking a person needs one minute, and two queues can be checked at the same time.
Picture from Wikimedia Commons
Two teams A
and
B
are going to travel by plane. Each team has
n
players, ranked from
1
to
n
according to their average performance. No two players in the same team share the same rank. Team
A
is waiting in queue
1
while team
B
is waiting in queue
2
. Nobody else is waiting for security check.
Little Q is the policeman who manages two queues. Every time he can check one person from one queue, or check one each person from both queues at the same time. He can't change the order of the queue, because that will make someone unhappy. Besides, if two players A
i![]()
and
B
j![]()
are being checked at the same time, satisfying
|A
i
−B
j
|≤k
, they will make a lot of noise because their rank are almost the same. Little Q should never let that happen.
Please write a program to help Little Q find the best way costing the minimum time.

Picture from Wikimedia Commons
Two teams A
Little Q is the policeman who manages two queues. Every time he can check one person from one queue, or check one each person from both queues at the same time. He can't change the order of the queue, because that will make someone unhappy. Besides, if two players A
Please write a program to help Little Q find the best way costing the minimum time.
Input
The first line of the input contains an integer
T(1≤T≤15)
, denoting the number of test cases.
In each test case, there are 2
integers
n,k(1≤n≤60000,1≤k≤10)
in the first line, denoting the number of players in a team and the parameter
k
.
In the next line, there are n
distinct integers
A
1
,A
2
,...,A
n
(1≤A
i
≤n)
, denoting the queue
1
from front to rear.
Then in the next line, there are n
distinct integers
B
1
,B
2
,...,B
n
(1≤B
i
≤n)
, denoting the queue
2
from front to rear.
In each test case, there are 2
In the next line, there are n
Then in the next line, there are n
Output
For each test case, print a single line containing an integer, denoting the minimum time to check all people.
Sample Input
1 4 2 2 3 1 4 1 2 4 3
Sample Output
7HintTime 1 : Check A_1. Time 2 : Check A_2. Time 3 : Check A_3. Time 4 : Check A_4 and B_1. Time 5 : Check B_2. Time 6 : Check B_3. Time 7 : Check B_4.
题意:现要检查两条队伍,有两种方式,一种是从两条队伍中任选一条检查一个人,第二种是在每条队伍中同时各检查一个,前提是两条队伍中的两个人的序号大于k。然后询问检查最少需要的时间。
题解:(不会做,看题解后做的,实力还是不行,多学多记,多学多记!)这道题首先给人感觉就是dp,其实也是这样的,但是会发现dp的话矩阵大小是6e4*6e4,时间空间上都不允许。于是机智的人就会发现,那个k非常的小,小到让人不敢相信,于是就对k做了无限yy。想到可以将dp分出来,那些差值小于k的直接暴力dp,复杂度也就o(nk),然后对于那些差值大于k的——在位置x和y为固定某个差值的情况小进行二分,找到理现在位置最近的一组x1、y1,使得其值之差小于k,则这个位置与初始位置的x、y之间的所有都是保证了两边的差值是大于k的,于是加为答案。(有点绕,具体看代码)
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <string>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <bitset>
#include <functional>
#include <cctype>
#include <utility>
#include <stack>
using namespace std;
typedef long long ll;
const int INF = 1e9+7;
const int maxn = 6e4+7;
int n,k;
int que1[maxn],que2[maxn],pos2[maxn];//两个队伍,以及第二个队伍每个人对应位置
bool cmp(int a,int b){return a>b;}
vector<int> g[2*maxn];
int dp[maxn][27];
int dfs(int x,int y){
if(!x||!y) return x+y;//如果某点为0,那么剩余的那个队伍就一个一个的减去
if(abs(que1[x]-que2[y])<=k){
int &v = dp[que1[x]][que1[x]-que2[y]+k];
if(v) return v;
return v = min(dfs(x-1,y),dfs(x,y-1))+1;
}//两个值之差小于k,暴力dp
vector<int>::iterator it = lower_bound(g[x-y+n].begin(),g[x-y+n].end(),x,cmp);//二分预先处理出来的数组。
if(it==g[x-y+n].end()) return max(x,y);//如果以该距离差剩下的不存在小于k的
int v = *it;
return dfs(v,y-x+v)+x-v;//把中间那些等距且差值大于k的加入
}
void solve(){
for(int i = n;i >= 1;i--){
for(int j = que1[i]-k;j <= que1[i]+k;j++){
g[i-pos2[j]+n].push_back(i);
}
}//处理出位置差为某个固定值且对应的值之差小于k的数组(vector)
memset(dp,0,sizeof(dp));
cout<<dfs(n,n)<<endl;
return ;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i = 0;i <= 2*n;i++) g[i].clear();
for(int i = 1;i <= n;i++){
scanf("%d",que1+i);
}
for(int i = 1;i <= n;i++){
scanf("%d",que2+i);
pos2[que2[i]] = i;
}//输入
solve();
}
return 0;
}