28屆寧波市中小學生程序設計競賽複賽(初中組)

第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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章