题目描述
小明是某RTS游戏的狂热爱好者,但是他从来不好好打游戏,经常搞出一些令人窒息的操作。一次,他竟然将自己的一个农夫派出去打野狼。
农夫初始时站在地图坐标(0,0)的位置,地图的出口的坐标为(n,n),地图上共有m只野狼,每只野狼有一个坐标(xi,yi),数据保证不会有两个野狼在相同的位置。农夫只有消灭地图上所有的野狼才能完成任务。
整个地图按y轴一共分为n层,当且仅当农夫清掉了本层的所有怪物之后才能到下一层,比如说,如果农夫当前的位置是(x,3),那么他必须将y坐标等于3的所有野狼消灭,才允许走到(x,4)。如果本层没有怪物,农夫能够直接到下一层。
由于小明使用的种族是Magyar,这个种族骁勇善战,农夫只需一击就能将野狼打死。因而,每到一个位置,如果这个位置有野狼,他可以直接将怪物秒掉(不需要任何操作)。
现在给出m个野狼的坐标,问农夫最少需要走多少步才能完成任务。农夫向上下左右移动一格算一步。
输入
第一行两个数n,m(n,m<=100,000)。 接下来m行,每行两个数,代表第i只野狼的坐标。
输出
第一行两个数n,m(n,m<=100,000)。 接下来m行,每行两个数,代表第i只野狼的坐标。
样例输入
4 5
1 1
2 1
1 2
3 2
3 3
样例输出
10
注意:
此题数据规模极大,后台25组数据,都是上万个坐标,而且狼的坐标(x,y)存在y>n的情况,还是我找bug的时候加了一行判断看看会不会tile,果然tle了…
正确代码:
25组测试点全过
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e6+10;
long long dp[MAX][2];//dp[i][0]表示left,dp[i][1]表示right
int data[MAX][2];//data[i][0]表示left,data[i][1]表示right
int n,m;
int Max;
inline long long min(long long a,long long b){
return a>b?b:a;
}
inline long long max(long long a,long long b){
return a>b?a:b;
}
inline int Calc(int a,int b){
return a-b>=0?a-b:0;
}
void init(){
memset(data,-1,sizeof(data));
cin>>n>>m;
int x,y;
data[0][0]=0;
data[0][1]=0;
Max=0;
for(int i=0;i<m;i++){
scanf("%d %d",&x,&y);
Max=Max>y?Max:y;
if(data[y][0]==-1){
data[y][0]=x;
data[y][1]=x;
}else{
data[y][0]=min(data[y][0],x);
data[y][1]=max(data[y][1],x);
}
}
}
void solve(){
int L=data[0][0],R=data[0][1];
dp[0][0]=2*(R-L);
dp[0][1]=R-L;
for(int i=1;i<=Max;i++){
int LL=data[i][0];
int RR=data[i][1];
if(LL==-1){
dp[i][0]=dp[i-1][0]+1;
dp[i][1]=dp[i-1][1]+1;
}else{
//dp[i][0]=min(L->LL,R->LL);
dp[i][0]=min(2*Calc(RR,L)+L-LL+dp[i-1][0]+1,2*Calc(RR,R)+R-LL+dp[i-1][1]+1);
//dp[i][1]=min(L->RR,R->RR);
dp[i][1]=min(2*Calc(L,LL)+RR-L+dp[i-1][0]+1,2*Calc(R,LL)+RR-R+dp[i-1][1]+1);
//cout<<"i="<<i<<":L:="<<L<<" R:"<<R<<" LL:"<<LL<<" RR="<<RR<<" dp[0]="<<dp[i][0]<<" dp[1]="<<dp[i][1]<<endl;
L=LL;
R=RR;
}
}
cout<<min(dp[Max][0]+abs(Max-n)+abs(L-n),dp[Max][1]+abs(Max-n)+abs(R-n))<<endl;
}
int main(){
init();
solve();
return 0;
}