Atcoder Beginner 085D 084D 題解

  首先說點題外話,認真的講,如果我大一就加了ACM,我現在肯定不是這麼菜的一個水平,晚了一年,什麼都晚了一步,很感謝教練,給了我一次參加ICPC的機會,對於已經大三的我,這個機會真的彌足珍貴,同樣,非常感謝在瀋陽賽區帶我拿銅的學長學姐,集訓隊的同學,大多數比我強不少,其中還有很多17級的學弟學妹,其實實力明明在我之上,但是沒機會出去比賽,目前也就沒牌可拿,所以在我這次拿了牌以後,除了欣喜之外,還有對這些學弟學妹的愧疚。講道理,我目前的實力,配不上這塊牌,但是即便是這次沒有拿牌,我也不會後悔做自費回家打比賽這個決定,因爲我覺得,機會來了,就要抓住,謀事在人成事在天,結果如何我無法左右,但我唯一知道的就是,到手的機會,絕對不能放開,如果如此首鼠兩端,那甚至就不配拿牌了。說到對集訓隊裏實力在我之上但卻沒有機會拿牌的同學,即便我沒有做錯什麼,我仍然是心裏有些慚愧的,所以目前我就選擇了掛機退役,希望把機會讓給這些有能力的同學出去比賽。但是即便這麼做了,我心裏還是有些過不去這個坎,不想面對某些沒法反駁的非議其實也是我退役的原因之一。所以,立一個不倒的flag吧,就當是心裏的救贖~ 讀研之前,我的能力一定會配得上這塊區域賽銅牌。好了~題外話就說到這吧~說出來了就坦然了許多~但是該面對的還是要面對,說到底,實力纔是最重要的。

  掛機之後並不想荒廢,所以打算每天做個一兩道題,今天還真就碰到兩個水題~真好~大致說下思路吧~

 

ABC 084 - D:https://abc084.contest.atcoder.jp/tasks/abc084_d

題意:

在1~1e5以內,有一種判定合法的方式:就是如果當前數 x 是素數,且 (x + 1) / 2也是素數,那麼這個數就是合法的。給你 q 個查詢區間,問你每段區間內存在多少個合法的數。

思路:

這題考點就是預處理配合前綴的使用,先枚舉1e5以內的素數,然後繼續枚舉合法的素數並且打上標記。記一個前綴數組cnt[maxx],作用是統計當前數之前有多少個合法的數(包括當前數在內),初始化第一項爲0,這是因爲第一項是1,1之前加上1本身沒有素數,然後cnt[i] += cnt[i - 1],如果當前數 i 被標記過,那就證明當前數本身合法,所以當前 cnt[i] 執行 ++,然後在每段查詢區間內,用 R 之前出現的合法數減去 L 之前出現的合法數,如果 L 本身合法,那結果再加1即可。

我的AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5;
const int Inf = 1 << 30;
int n;
int l, r;
int p[maxx + 7];
int dd[maxx + 7];
bool vis[maxx + 7];
int cnt[maxx +7];
int ans;

void solve() {
    int t = 0;
    for(int i = 2; i <= maxx; i++) {
        bool flg = 1;
        for(int j = 2; j <= sqrt(i); j++) {
            if(i % j == 0) {
                flg = 0; break;
            }
        }
        if(flg) {
            p[++t] = i;
            vis[p[t]] = 1;
        }
    }
    int f = 0;
    for(int i = 3; i <= maxx; i++) {
        if(vis[i]) {
            int tmp = (i + 1) / 2;
            if(vis[tmp]) dd[++f] = i;
        }
    }
    memset(vis, 0, sizeof(vis));
    for(int i = 1; i <= f; i++) vis[dd[i]] = 1;
    cnt[1] = 0;
    for(int i = 2; i <= maxx; i++) {
        cnt[i] += cnt[i - 1];
        if(vis[i]) cnt[i]++;
    }
}

int main() {
    solve();
    cin >> n;
    while(n--) {
        cin >> l >> r;
        if(vis[l]) ans = cnt[r] - cnt[l] + 1;
        else ans = cnt[r] - cnt[l];
        cout << ans << endl;
    }
}

 

ABC 085 - D:https://abc085.contest.atcoder.jp/tasks/abc085_d

題意:

你有 n 把武器,怪獸有 h 滴血,第 i 把武器有兩個屬性,揮動傷害值 a[i],以及投擲傷害值 b[i]( a[i] <= b[i] )。每把武器的揮動傷害都能任意進行若干次,但是每把武器的投擲傷害,只能進行一次,問,最少幾步打死怪獸。

思路:

這題考點就是結構體排序,由於 b[i] 的值較大,且只能進行換一次,那麼我就從大往小消耗 b[i],而 a[i] 可以進行無限多次,那麼若想步數最少,那就每次揮動傷害都進行最大的a[i]即可。換句話說,提供傷害的是某些 b[i] 和最大的 a[i],再仔細想下,這某些b[i],就是比最大的 a[i] 還要大的b[i],那麼我先消耗他們,到了最大的a[i]的這個值的時候,我就不斷揮動傷害,直到怪獸死亡,比它小的 b[i] 就不用進行多餘的消耗了。那我採取的處理方式是,將 b[n + 1] 這項賦值成 a[i] 的最大值 max0,然後對這 n + 1 項,以 b[i] 降序進行結構體排序,然後,按照上述紅色加粗的操作模擬一下就ok啦~

我的AC代碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 7;
const int Inf = 1 << 30;
int n, h;
int ans;

struct PP {
    int a;
    int b;
} p[maxx];

bool cmp(PP x, PP y) { return x.b > y.b; }

int main() {
    cin >> n >> h;
    int max0 = 0;
    for(int i = 1; i <= n; i++) {
        cin >> p[i].a >> p[i].b;
        max0 = max(max0, p[i].a);
    }
    p[n + 1].a = 0, p[n + 1].b = max0;
    sort(p + 1, p + n + 2, cmp);
    for(int i = 1; i <= n + 1; i++) {
        if(p[i].b > max0) {
            ans++;
            h -= p[i].b;
        }
        else if(p[i].b == max0) {
            ans += h / max0;
            if(h % max0) ans++;
            h -= ans * max0;
        }
        if(h <= 0) break;
    }
    cout << ans << endl;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章