1. 程式人生 > >「日常訓練」Woodcutters(Codeforces Round 303 Div.2 C)

「日常訓練」Woodcutters(Codeforces Round 303 Div.2 C)

答案 cpp break lse 策略 -c else if bool else

這題慘遭被卡。。卡了一個小時,太真實了。

題意與分析 (Codeforces 545C)

題意:給定\(n\)棵樹,在\(x\)位置,高為\(h\),然後可以左倒右倒,然後倒下去會占據\([x-h,x]\)或者\([x,x+h]\)區間,如果不砍伐,占據\([x,x]\)區域。
問你最多砍多少棵樹,砍樹的條件是倒下去後占有的區間不能被其他樹占據。

分析:在這條題目的條件下,這是一個傻逼貪心題。(然後我讀錯兩次題目,怎麽也想不出來貪心策略。。。。)
很簡單的策略:能往左倒往左倒,能往右倒往右倒。因為樹的倒下無論如何只會影響額外的一棵樹!!(換句話說,如果說倒下的區間不用考慮樹的存在,就很有意思了)舉個例子,考慮一種極端情況:第\(i\)

棵樹到第\(n\)棵樹如果挨個往左倒正好完美覆蓋。那麽這種情況下你第\(i-1\)棵樹如果可以往右倒照樣可以往右倒,因為每棵樹的倒下只影響另外左右一個樹,那麽我大不了第\(i\)棵樹不倒,我的答案不會更差。這樣就確定了貪心策略的正確性。

代碼

#include <bits/stdc++.h>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (repType i = (a); i <= (b); ++i)
#define per(i, a, b) for (repType i = (a); i >= (b); --i)
#define QUICKIO                      ios::sync_with_stdio(false);     cin.tie(0);                      cout.tie(0);
using namespace std;
using ll=long long;
using repType=int;

int main()
{
    int n; cin>>n;
    pair<int,int> tree[100005];
    rep(i,1,n) cin>>tree[i].fi>>tree[i].se;
    int cnt=0;
    int npos=0,ntree=1;
    int cut[100005]; ZERO(cut);
    rep(i,1,n)
    {
        int l_boundary=tree[i].fi-tree[i].se,
            r_boundary=tree[i].fi+tree[i].se;
        bool lok=true;
        per(j,i-1,1)
        {
            if(tree[j].fi>=l_boundary || (cut[j]==2&&tree[j].fi+tree[j].se>=l_boundary)) 
            {
                lok=false; break;
            }
            if(tree[j].fi+tree[j].se<l_boundary) break;
        }
        if(lok) { cut[i]=1; continue; } 
        bool rok=true;
        rep(j,i+1,n)
        {
            if(tree[j].fi>r_boundary) break;
            else if(tree[j].fi<=r_boundary) {rok=false; break;}
        }
        if(rok) cut[i]=2;
    }
    int ans=0;
    rep(i,1,n) if(cut[i]) ans++;
    cout<<ans<<endl;
    return 0;
}

「日常訓練」Woodcutters(Codeforces Round 303 Div.2 C)