1. 程式人生 > 實用技巧 >新生周賽第四周題解

新生周賽第四周題解

A.

B.

C.

D.

E.

F.

G.

H.佐倉綾音的號哭

  此題是放ak題,不過用到的演算法只是最基礎的二分和貪心,主要還是考驗同學們的思維能力。如果還有同學不會二分的話,建議先去學習一下。
  首先要打敗一個分身,我們必須使用一個力量不小於分身能力值的成員,在保證這個前提下,儘量使用耐力值比較大的成員。其實我們不必糾結選出哪個耐力值比較大的同學,這樣的話題目的難度會加大,我們只要知道什麼時候需要換人,什麼時候不需要換人就行了。
  首先我們需要宣告一個結構體陣列來儲存每個成員的力量和耐力,然後按每個成員的力量從小到大排序,因為我們是按力量的大小來排序的,那麼這位成員以後的成員的力量自然也不小於當前分身的能力值。設當前的位置是i,我們再建立一個數組,用來儲存從i到n中的所有成員中的最大的耐力值,然後在用一個變數days來存一下當前成員用掉的耐力值。這樣,我們用二分快速查找出一個最小的力量不小於當前分身能力值的成員的下標i,於是我們就得到了一個解集,這個解集中的所有的成員力量都不小於當前分身的能力值,且他們最大的耐力值是k,對於下一個分身,如果我們當前解集中的成員的力量不夠或者耐力值不夠了,那麼我們就需要繼續向後查找了,這時候就有幾種情況:
  1.力量最大的成員的力量小於某個分身,無解。
  2.力量夠,耐力值夠。肯定還能打,繼續下一個分身。
  3.力量夠,耐力值不夠。這種情況我們這一天肯定是沒法打了,只能下一天繼續打,於是我們進行一次二分,然後更新現在解集的能力值和耐力值上限以及當前成員用掉的耐力值days,同時答案+1。
  4.力量不夠,耐力值也不夠。這種情況和上一種一樣。
  5.力量不夠,但是耐力值還夠。這時候我們也需要二分再找一個成員,這個成員打敗的分身數量將會繼承上一個成員打敗的分身數量,如果這個成員的耐力值不夠打敗那麼多分身,那麼之前的分身只能由前一天的成員來打,這個成員屬於下一天,更新現在解集的能力值和耐力值以及days,同時答案+1。否則的話,只更新解集的能力值即可。

const int maxn = 2e5+10;
const int maxm = 2e2+10;
struct IF {
    int x, cnt;
} info[maxn], arr[maxn]; int post[maxn];
int main() {
    int t; cin >> t;
    while(t--) {
        int n; cin >> n;
        for (int i = 1; i<=n; ++i) scanf("%d", &arr[i].x); 
        int m; cin >> m;
        for (int i = 1; i<=m; ++i) scanf("%d%d", &info[i].x, &info[i].cnt);
        sort(info+1, info+m+1, [](IF a, IF b) {return a.x<b.x;});
        post[m+1] = 0;
        for (int i = m; i>=1; --i) post[i] = max(post[i+1], info[i].cnt);
        int damage = 0, cnt = 0, days = 0, ans = 0;
        for (int i = 1; i<=n; ++i) {
            ++cnt;
            if (days<cnt || damage<arr[i].x) {
                int p = lower_bound(info+1, info+m+1, arr[i], [](const IF &a, const IF &b) {return a.x<b.x;})-info;
                if (p==m+1) {
                    cout << -1 << endl; goto out;
                }
                if (days<cnt) ++ans, cnt = 1;
                days = post[p], damage = info[p].x;
                if (days<cnt) ++ans, cnt = 1;
            }
        }
        cout << ans << endl;
        out:;
    }
    return 0;   
}

I. 末日時在做什麼?有沒有空?可以來拯救嗎?

  略過,不會寫。

J.zjl姐姐的微笑

  求極限的公式相當於求一個無限大的矩形能放粉色氣球的最大比例。我們可以用下圖中的放置方法來放置整個矩形
,對於處於非邊界區域的位置,顯然有2/3的地方可以放置粉色氣球,而對於邊界區域的位置,則可放置的數量會少於2/3,但是我們的矩形是無限大的,所以當n和m趨近於正無窮的時候,答案就是2/3。題目要保留20為有效數字,自然不能寫分數,那就只能是小數,但是因為double的有效位數不夠用,所以直接輸出3.0/2.0也是不對的,可以用字串輸出答案,即

    printf("0.66666666666666666667\n");