第4題-迷宮大門
來源於寧波市程序設計競賽複賽(初中組)
n≤500,000,顯然對於這麼大的n,O(n^2)的解法都不夠。那麼考慮O(n)或者O(n*lg(n))的解法,動態規劃?貌似可行,但狀態怎麼表示?左對齊?右對齊?除此,要怎麼進行轉移呢,畢竟a和b的範圍也相當大,即便進行hash,最多也有500,000?
繼續分析發現,題目中指出,每一處對齊都只得1分,這說明在左右不可能同時對齊的情況下,左對齊和右對齊的收益是一樣的。那我們不妨讓所有小球都儘量左對齊好了,直到某一處不能左對齊便從後一個開始繼續左對齊,反證法可以證明這樣能得到最大收益。
對齊實際上是保持高度相等,例如對於第一根繩子上的右小球,可以保持的高度範圍是[0,a1+b1],第二根繩子的左小球可以保持的高度範圍是[0,a2+b2]。
要是這兩個小球保持高度相等,那麼我們必須保證他們的高度在[0,min(a1+b1,a2+b2)]範圍內,相應地,第二根繩子的右小球變化範圍就必須是[a2+b2-min(a1+b1,a2+b2),a2+b2]…..依次類推,每兩個相鄰小球可以對齊便計1分,不能對齊便跳過,下一個繼續對齊。
#include <iostream>
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <math.h>
using namespace std;
const int maxn=5e5+15;
int l[maxn], r[maxn];
bool ok(int s1,int t1,int s2,int t2){
int s=max(s1,s2);
int t=min(t1,t2);
if(s<=t) return true;
return false;
}
int main()
{
int n;
freopen("door.in","r",stdin);//從in.txt中讀取數據
freopen("door.out","w",stdout);//輸出到out.txt文件
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&l[i],&r[i]);
int ma=l[1]+r[1], mi=0;
int ans=0;
for(int i=2;i<=n;i++){
if(ok(mi,ma,0,l[i]+r[i])){
ans++;
int len=l[i]+r[i];
int tmi=max(0,len-ma);
int tma=max(0,len-mi);
mi=tmi;
ma=tma;
}else{
mi=0;
ma=l[i]+r[i];
}
// printf("%d %d %d\n",ans, mi, ma);
}
printf("%d\n",ans);
return 0;
}