Atcoder Beginner 119D 122C 题解(都是二分)

题意:

给你一个n,一个m,表示有n个景点1,和m个景点2,q个查询,表示你每次的位置。你想要至少游览景点1和景点2各一个,问你最小花费。

思路:

二分处理一下,分别处理当前查询的位置的前后的景点1和景点2,然后

前1,前2; 前1,后2;

前2,前1;前2,后1;

后1,前2;后1,后2;

后2,前1;后2,后1。

8种方式维护一个最小值就ok了。

这里提一下,upper_bound() 和 lower_bound() 使用的时候,一般都初始化第一项的前一项和最后一项的后一项(防止查不到下标的情况),具体值因题而定。

我的AC代码:

#include
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 7;
const int Inf = 1 << 30;
const ll INF = 1ll << 60;
int a, b, q;
ll s[maxx], t[maxx], dd;

int main() {
    scanf("%d %d %d", &a, &b, &q);
    for(int i = 1; i <= a; i++) scanf("%lld", &s[i]);
    for(int i = 1; i <= b; i++) scanf("%lld", &t[i]);
    s[0] = s[1], t[0] = t[1];
    s[a + 1] = s[a], t[b + 1] = t[b];
    while(q--) {
        scanf("%lld", &dd);

        int cnt1 = upper_bound(s + 1, s + a + 1, dd) - s;
        cnt1 = a - cnt1 + 1; //s中有cnt1个比dd大的

        int cnt2 = upper_bound(t + 1, t + b + 1, dd) - t;
        cnt2 = b - cnt2 + 1; //t中有cnt2个比dd大的

        ll res = 0;
        ll ans1 = abs(dd - s[a - cnt1]);
        ll ans2 = abs(dd - s[a - cnt1 + 1]);
        ll res1 = abs(s[a - cnt1] - t[b - cnt2]);
        ll res2 = abs(s[a - cnt1 + 1] - t[b - cnt2]);
        res = min(ans1 + res1, ans2 + res2);

        ans1 = abs(dd - s[a - cnt1]);
        ans2 = abs(dd - s[a - cnt1 + 1]);
        res1 = abs(s[a - cnt1] - t[b - cnt2 + 1]);
        res2 = abs(s[a - cnt1 + 1] - t[b - cnt2 + 1]);
        ll tmp1 = min(ans1 + res1, ans2 + res2);
        res = min(res, tmp1);

        ans1 = abs(dd - t[b - cnt2]);
        ans2 = abs(dd - t[b - cnt2 + 1]);
        res1 = abs(t[b - cnt2] - s[a - cnt1]);
        res2 = abs(t[b - cnt2 + 1] - s[a - cnt1]);
        ll tmp2 = min(ans1 + res1, ans2 + res2);
        res = min(res, tmp2);

        ans1 = abs(dd - t[b - cnt2]);
        ans2 = abs(dd - t[b - cnt2 + 1]);
        res1 = abs(t[b - cnt2] - s[a - cnt1 + 1]);
        res2 = abs(t[b - cnt2 + 1] - s[a - cnt1 + 1]);
        ll tmp3 = min(ans1 + res1, ans2 + res2);

        res = min(res, tmp3);
        cout << res << endl;
    }
}

 

GeT AC

题意:

给一个长度为n的串s,q个查询输入L和R,问你在s[L]到s[R]之间,出现多少次捆绑的"AC"。

思路:

所求即为当前输入的R之前出现的AC的个数减去L之前出现的AC的个数即可,那么二分搞一下就ok了。

先将所有捆绑出现的AC的A的位置存进pos数组中,然后

int cntr = lower_bound(pos + 1, pos + tot + 1, r) - pos; //pos中第一个大于等于r的下标

这样得出第一个大于等于R的AC的pos的下标(pos的下标表示AC出现的个数),即超过R的第一个AC以及之前出现的AC个数,故cntr--,就得到R之前出现AC的次数。

同理

int cntl = lower_bound(pos + 1, pos + tot + 1, l) - pos; //pos中第一个大于等于l的下标

cntl--得到L之前出现的AC的个数

cntr - cntl 就是答案。

我的AC代码:

#include
using namespace std;
typedef long long ll;
const int maxx = 1e5 + 22;
const int Inf = 1 << 30;
const ll INF = 1ll << 60;
priority_queue qua;
vector vec;
int n, q;
char s[maxx];
int l, r;
int pos[maxx];
 
int main() {
    scanf("%d %d", &n, &q);
    scanf("%s", s + 1);
    s[n + 1] = 'A', s[n + 2] = 'C';
    int tot = 0;
    for(int i = 1; i < n + 2; i++) {
        if(s[i] == 'A' && s[i + 1] == 'C') pos[++tot] = i;
    }
    while(q--) {
        scanf("%d %d", &l, &r);
        int cntr = lower_bound(pos + 1, pos + tot + 1, r) - pos; //pos中第一个大于等于r的下标
        cntr--; //r之前AC的个数
        int cntl = lower_bound(pos + 1, pos + tot + 1, l) - pos; //pos中第一个大于等于l的下标
        cntl--; //l之前AC的个数
        //printf("%d %d\n", cntl, cntr);
        printf("%d\n", cntr - cntl);
    }
}

你可能感兴趣的:(At,Beginner,&,Grand)