2018徐州网络赛-菜鸡补题

I.Characters with Hash
签到题。消掉前缀零,特判一下差小于10的情况和全0的情况即可。

ac代码:

#include
using namespace std;

char p, s[1000005];

int main() {
    int t, n;
    scanf("%d", &t);
    while(t--) {
        scanf("%d\n%c%s", &n, &p, s);
        int i = 0, len = strlen(s), ans;
        while(i < len && p - s[i] == 0) {
            i++;
        }
        ans = (len - i) * 2;
        if(p - s[i] < 10){
            ans -= 1;
        }
        if(ans <= 0) {
            ans = 1;
        }
        printf("%d\n", ans);
    }
    return 0;
}

B. BE, GE or NE

博弈题。

但是这题比较强,传统的博弈题只分胜负,最多加个平手,而这题随着最后游戏分数的区间不同,划分三种结局!!!

从传统的角度把这题抽象一下,就是好像有一根指针,在区间上移动,最后停下的位置代表着结局。如果逆向思维一下,把这跟指针看成相对静止,变成区间在移动的话……

三种操作,加,减,乘-1随着当前玩家的不同,就变成了另外一种东西。

对于希望得到GE的玩家:

加:GE区间扩大,BE区间缩小直至消失,消失后压缩NE区间

减:与加相反,BE区间扩大。

乘-1:区间翻转。

对于希望得到BE的玩家:

呃,跟楼上相反,乘-1还是区间翻转。

然后我们分别考虑这三种走法对区间的影响,最后取个并,就是当前的最理想结局。

用字符串模拟,最后判一下s[m]是什么状态,即可得到结果。

%%权哥!

ac代码:

#include
using namespace std;

const int maxn = 1005;

struct Query {
    int a, b, c;
} q[maxn];

int main() {
    // k,GE;l,BE
    int n, m, k, l;
    char a[205], b[205], c[205], s[205];
    scanf("%d%d%d%d", &n, &m, &k, &l);
    for(int i = 1; i <= n; i++) {
        scanf("%d%d%d", &q[i].a, &q[i].b, &q[i].c);
    }
    m += 100;
    k += 100;
    l += 100;
    for(int i = 0; i <= l; i++) {
        s[i] = 'B';
    }
    for(int i = l + 1; i < k; i++) {
        s[i] = 'N';
    }
    for(int i = k; i <= 200; i++) {
        s[i] = 'G';
    }
    for(int num = n; num > 0; num--) {
        if(q[num].a > 0) {
            for(int i = 0; i <= 200; i++) {
                a[i] = s[200];
            }
            for(int i = 0; i <= 200 - q[num].a; i++) {
                a[i] = s[i + q[num].a];
            }
        }
        if(q[num].b > 0) {
            for(int i = 0; i <= 200; i++) {
                b[i] = s[0];
            }
            for(int i = q[num].b; i <= 200; i++) {
                b[i] = s[i - q[num].b];
            }
        }
        if(q[num].c > 0) {
            for(int i = 0; i <= 200; i++) {
                c[i] = s[200 - i];
            }
        }
        // 判断当前是谁在走
        if(num & 1) {
            for(int i = 0; i <= 200; i++) {
                s[i] = 'B';
                if((q[num].a && a[i] == 'G') || (q[num].b && b[i] == 'G') || (q[num].c && c[i] == 'G')) {
                    s[i] = 'G';
                    continue;
                }
                if((q[num].a && a[i] == 'N') || (q[num].b && b[i] == 'N') || (q[num].c && c[i] == 'N')) {
                    s[i] = 'N';
                }
            }
        } else {
            for(int i = 0; i <= 200; i++) {
                s[i] = 'G';
                if((q[num].a && a[i] == 'B') || (q[num].b && b[i] == 'B') || (q[num].c && c[i] == 'B')) {
                    s[i] = 'B';
                    continue;
                }
                if((q[num].a && a[i] == 'N') || (q[num].b && b[i] == 'N') || (q[num].c && c[i] == 'N')) {
                    s[i] = 'N';
                }
            }
        }
    }

    if(s[m] == 'G') {
        printf("Good Ending\n");
    } else if(s[m] == 'B') {
        printf("Bad Ending\n");
    } else {
        printf("Normal Ending\n");
    }
    return 0;
}

H.Ryuji doesn’t want to study

主要就是搞那个式子,我不会化简,我看网上有人化到最后得出“这不就是俩前缀和嘛”的结论。

怎么说,线段树维护区间和和权值和就好了。

ac代码:

#include
using namespace std;
typedef long long ll;

const int maxn = 1e5 + 5;

struct Ans {
    ll sum, val;
};

int n, q;
ll in[maxn], sum[maxn << 2], val[maxn << 2];

void pushUp(int i) {
    sum[i] = sum[i << 1] + sum[i << 1 | 1];
    val[i] = val[i << 1] + val[i << 1 | 1];
}

void build(int i, int l, int r) {
    if(l == r) {
        sum[i] = in[l];
        val[i] = in[l] * (n - l + 1);
        return;
    }
    int mid = (l + r) / 2;
    build(i << 1, l, mid);
    build(i << 1 | 1, mid + 1, r);
    pushUp(i);
}

void update(int i, int l, int r, int pos, ll v) {
    if(l == r) {
        sum[i] = v;
        val[i] = v * (n - pos + 1);
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) {
        update(i << 1, l, mid, pos, v);
    } else {
        update(i << 1 | 1, mid + 1, r, pos, v);
    }
    pushUp(i);
}

Ans query(int i, int l, int r, int L, int R) {
    if(l >= L && r <= R) {
        return {sum[i], val[i]};
    }
    int mid = (l + r) >> 1;
    Ans left = {0, 0}, right = {0, 0};
    if(L <= mid) {
        left = query(i << 1, l, mid, L, R);
    }
    if(R > mid) {
        right = query(i << 1 | 1, mid + 1, r, L, R);
    }
    return {left.sum + right.sum, left.val + right.val};
}


int main() {
    scanf("%d%d", &n, &q);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &in[i]);
    }
    build(1, 1, n);
    int a, b, c;
    while(q--) {
        scanf("%d%d%d", &a, &b, &c);
        if(a == 1) {
            Ans ans = query(1, 1, n, b, c);
            printf("%lld\n", ans.val - ans.sum * (n - c));
        } else {
            update(1, 1, n, b, c);
        }
    }
    return 0;
}

你可能感兴趣的:(ACM,博弈论,模拟,线段树)