CSA Round #40 (Div. 2 only)

来源:互联网 发布:淘宝宝贝失效了已付款 编辑:程序博客网 时间:2024/06/05 19:11

Erase Value

题意:

给出N个数,每个数都在[1, 1000]范围内,选择一个数,删除这N个数中出现的所有该数,使得所剩数的和最小

分析:

暴力?

代码:

int d[1010];int main(){    int n, x, mx = 0, s = 0;    scanf("%d", &n);    for (int i = 0; i < n; i++) {        scanf("%d", &x);        s += x;        d[x] += x;        mx = max(mx, d[x]);    }     printf("%d\n", s - mx);}

Move the Bishop

题意:

在8*8棋盘中,移动仅限对角线移动,求某个点到另一个点的最小移动次数

分析:

BFS?
题解是按照棋盘的染色来判定,只有同色才可达,否则不可达。可达情况下,相同点答案为0,若在同一对角线上则答案为1,否则为2(可以证明任意两个同色点所在四条对角线的上侧交点和下侧交点必然至少有一个在棋盘范围内)

代码:

// BFS#define maxn 10int d[maxn][maxn], v[maxn][maxn];int dr[4][2] = {-1, 1, 1, -1, 1, 1, -1, -1};queue<int> qx;queue<int> qy;void work(int x, int y) {    qx.push(x);    qy.push(y);    v[x][y] = 1;    while (!qx.empty()) {        int sx = qx.front(), sy = qy.front();        qx.pop();qy.pop();        for (int i = 1; i <= 8; i++) {            for (int j = 0; j < 4; j++) {                int ex = sx + dr[j][0] * i,                     ey = sy + dr[j][1] * i;                if (ex > 0 && ex <= 8 && ey > 0 && ey <= 8 && !v[ex][ey]) {                    d[ex][ey] = d[sx][sy] + 1;                    qx.push(ex);                    qy.push(ey);                    v[ex][ey] = 1;                }            }        }    }} int main(){    int x, y, z, p;    scanf("%d%d%d%d", &x, &y, &z, &p);    memset(d, -1, sizeof d);    d[x][y] = 0;    work(x, y);    printf("%d\n",d[z][p]);}
// Colorint main(){    int a, b, c, d;    scanf("%d%d%d%d", &a, &b, &c, &d);    if ((a + b) % 2 != (c + d) % 2) {        puts("-1");    } else {        if (a == c && b == d) {            puts("0");        } else if (b - a == d - c || a + b == c + d) {            puts("1");        } else {            puts("2");        }    }}

Switch the Lights

题意:

有N个灯,初始状态给定,有N个开关,第i个开关的控制范围为[i,Ri],花费为Ci, 求出使得所有灯关闭的最小费用,若无法关闭所有灯则输出-1

分析:

处理到第i个灯时其前i-1个灯必然要全部关闭,而第i次操作要使第i个灯关闭,如果该灯现在就是关闭的则不使用该开关,否则使用该开关。所以只有一个固定的结果,不存在最优值,也不会出现无解的情况。
直接思路就是线段树区间add单点查询,记录该灯被操作的次数,复杂度O(nlogn)
另一种方法记录边界,state变量记录操作了几次,操作开关或者遇到操作边界则修改state。

代码:

// segment tree + lazy   O(n * logn)#define maxn 100010struct tree {    int le, rig;    int sum, cov;} t[maxn << 2];void build(int id, int l, int r) {    t[id].le = l;    t[id].rig = r;    t[id].cov = 0;    if (l == r) {        t[id].sum = 0;        return;    }    int mid = (l + r) >> 1;    build(id * 2, l, mid);    build(id * 2 + 1, mid + 1, r);    t[id].sum = t[id * 2].sum + t[id * 2 + 1].sum;}void update(int id, int l, int r, int val) {    if (t[id].le == l && t[id].rig == r) {        t[id].cov += val;        return;    }    int mid = (t[id].le + t[id].rig) >> 1;    t[id].sum += t[id].cov * (t[id].rig - t[id].le + 1) + val * (r - l + 1);    t[id * 2].cov += t[id].cov;    t[id * 2 + 1].cov += t[id].cov;    t[id].cov = 0;    if (r <= mid) {        update(id * 2, l, r, val);    } else if (l > mid) {        update(id * 2 + 1, l, r, val);    } else {        update(id * 2, l, mid, val);        update(id * 2 + 1, mid + 1, r, val);    }}int query(int id, int l, int r) {    if (t[id].le == l && t[id].rig == r) {        return t[id].sum + t[id].cov * (t[id].le + t[id].rig - 1);    }    int mid = (t[id].le + t[id].rig) >> 1;    t[id].sum += t[id].cov * (t[id].rig - t[id].le + 1);    t[id * 2].cov += t[id].cov;    t[id * 2 + 1].cov += t[id].cov;    t[id].cov = 0;    if (r <= mid) {        return query(id * 2, l, r);    } else if (l > mid) {        return query(id * 2 + 1, l, r);    } else {        return query(id * 2, l, mid) + query(id * 2 + 1, mid + 1, r);    }}char s[maxn];int b[maxn];int main(){    int n, x;    ll ans = 0;    scanf("%d", &n);    build(1, 1, n);    scanf("%s", s);    for (int i = 1; i <= n; i++) {        scanf("%d", &b[i]);    }    for (int i = 1; i <= n; i++) {        scanf("%d", &x);        int y = query(1, i, i);        if ((y & 1) && s[i - 1] == '0' || !(y & 1) && s[i - 1] == '1') {            ans += x;            update(1, i, b[i], 1);        }    }    printf("%lld\n", ans);}
// O(n)#define maxn 100010int a[maxn], b[maxn];char s[maxn];int main() {    int n, x, state = 0;    ll ans = 0;    scanf("%d%s", &n, s);    for (int i = 1; i <= n; i++) {        scanf("%d", &a[i]);    }       for (int i = 1; i <= n; i++) {        scanf("%d", &x);        if (state ^ (s[i - 1] - '0')) {            state ^= 1;            b[a[i]] ^= 1;            ans += x;        }        state ^= b[i];    }    printf("%lld\n", ans);}

Restricted Permutations

题意:

N个数,每个数与其后一个数的相对位置给定(其前或其后),求满足条件的排列的数目

分析:

DP,用d[i][j]记录处理完第i位置,其前面有j个数的排列的数目
状态转移:如果a[i]为1,则其应在i-1的后面,对i-1中的每个j,i可以扩展出来的状态为j+1..i1。 如果a[i]为0,则其应在i-1的前面,对i-1中的每个j,i可以扩展出来的状态为0..j

代码:

#define mod 1000000007#define maxn 2010int n, a[maxn];ll ans, d[maxn];int main(){    scanf("%d", &n);    memset(d, 0, sizeof d);    d[0] = 1;    for (int i = 1; i < n; i++) {        scanf("%d", &a[i]);        if (a[i] == 1) {            ll x = d[0];            for (int j = 1; j <= i; j++) {                ll y = (x + d[j]) % mod;                d[j] = x % mod;                x = y;            }            d[0] = 0;        } else {            ll x = 0;            for (int j = i; j >= 0; j--) {                x = (x + d[j]) % mod;                d[j] = x % mod;            }        }    }     for (int i = 0; i <= 2000; i++) {        ans = (ans + d[i]) % mod;    }    printf("%lld\n", ans);}

Direct the Graph

待补