翘课报名了CCSP2019的比赛,上次去分赛区觉得还挺好玩的这个比赛,但是由于比较菜不会读二进制文件也不开多线程就比较自闭。这次做点准备吧。

ccsp官网都可以拿到题面和数据 http://history.ccfccsp.org.cn/

T1 简单的BFS不难发现每一轮每个人走到安全区就不会掉血了,所以每个人的终点其实是安全区。然后从安全区开始往外走就好了。注意不能斜着走左右两侧都是障碍物的。

#include<iostream>
#include<cstdio>
#include<cstring>
#include <queue>

#define ll long long
#define maxn 410
#define maxm 200010
using namespace std;
ll n, m, e, f, h;
ll g[maxn][maxn];
ll pos[maxm][2];
ll val[maxn][maxn];
ll hp[maxm];
struct node {
    ll x, y;
} E[maxm];
queue<node> q;
ll xx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
ll yy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

ll Cal(node p1, node p2) {
    return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}

int main() {
    freopen("cs.in", "r", stdin);
//    freopen(".ans", "w", stdout);
//    freopen("C:\\Users\\yanli\\Desktop\\data\\10.in", "r", stdin);
    freopen("cs.ans", "w", stdout);

    scanf("%lld%lld%lld%lld%lld", &n, &m, &e, &f, &h);
    for (ll i = 1; i <= m; i++)hp[i] = h;
    ll x, y;
    for (ll i = 1; i <= e; i++) {
        scanf("%lld%lld", &x, &y);
        E[i].x = x;
        E[i].y = y;
    }
    for (ll i = 1; i <= m; i++)
        scanf("%lld%lld", &pos[i][0], &pos[i][1]);
    while (f--) {
        ll rx, ry, r;
        scanf("%lld%lld%lld", &rx, &ry, &r);
        for (ll i = 1; i <= e; i++)
            if (Cal(E[i], node{rx, ry}) <= r * r)g[E[i].x][E[i].y] = 0;
            else g[E[i].x][E[i].y] = 1;
        memset(val, -1, sizeof(val));
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                if(Cal(node{rx,ry},node{i,j})<=r*r){
                    q.push(node{i,j});
                    val[i][j]=0;
                }
        while (!q.empty()) {
            node now = q.front();
            q.pop();
            for (ll i = 0; i < 8; i++) {
                ll nx = now.x + xx[i];
                ll ny = now.y + yy[i];
                if (nx >= 0 && nx < n && ny >= 0 && ny < n && val[nx][ny] == -1) {
                    if (i == 0 && g[now.x - 1][now.y] && g[now.x][now.y - 1])continue;
                    if (i == 2 && g[now.x - 1][now.y] && g[now.x][now.y + 1])continue;
                    if (i == 5 && g[now.x + 1][now.y] && g[now.x][now.y - 1])continue;
                    if (i == 7 && g[now.x + 1][now.y] && g[now.x][now.y + 1])continue;
                    val[nx][ny] = val[now.x][now.y] + 1;
                    if (g[nx][ny] == 0)q.push(node{nx, ny});
                }
            }
        }
        for (ll i = 1; i <= m; i++)
            hp[i] -= val[pos[i][0]][pos[i][1]];
        for (ll i = 1; i <= m; i++) {
            scanf("%lld%lld", &x, &y);
            pos[i][0] = x;
            pos[i][1] = y;
        }
    }
    for (ll i = 1; i <= m; i++)
        printf("%lld\n", max(0ll, hp[i]));
    return 0;
}

T2 emmmm算是不难的模拟把,我用的是set,常数写的有点大了,2s左右的时间,过几天再加一个优化版本吧(8可能的咕咕咕)。由于两次find点的策略不一样,且不能合起来(应该不能把),所以我开了两个set,然后删点的时候更新其他点的信息。

#include<bits/stdc++.h>

#define maxn 100010
using namespace std;
int n, m;
int r[maxn], c[maxn];
int dl[maxn];

struct node {
    int u, r;

    bool operator<(node A) const {
        if (r != A.r)return r < A.r;
        return u < A.u;
    }
};

struct Node {
    int u, r, c;

    bool operator<(Node A) const {
        if (r != A.r)return r > A.r;
        if (c != A.c)return c > A.c;
        return u > A.u;
    }
};

set<node> s;
set<Node> ss;
vector<int> G[maxn];

int init() {
    int x = 0, f = 1;
    char s = getchar();
    while (s < '0' || s > '9') {
        if (s == '-')f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9') {
        x = x * 10 + s - '0';
        s = getchar();
    }
    return x * f;
}

void up(int u, int r1, int r2, int c1, int c2) {
    auto p1 = (*s.lower_bound(node{u, r1}));
    s.erase(p1);
    p1.r = r2;
    s.insert(p1);
    r[u] = r2;

    auto p2 = (*ss.lower_bound(Node{u, r1, c1}));
    ss.erase(p2);
    p2.r = r2;
    p2.c = c2;
    ss.insert(p2);
    r[u] = r2;
    c[u] = c2;
}

void del(int now) {
    dl[now] = 1;
    for (int v:G[now]) {
        if (dl[v])continue;
        up(v, r[v], r[v] - 1, c[v], c[v] - (r[now] == 2));
        if (r[v] == 2) {
            for (int k:G[v]) {
                if (dl[k])continue;
                up(k, r[k], r[k], c[k], c[k] + 1);
            }
        } else if (r[v] == 1) {
            for (int k:G[v]) {
                if (dl[k])continue;
                up(k, r[k], r[k], c[k], c[k] - 1);
            }
        }
    }
    s.erase(node{now, r[now]});
    ss.erase(Node{now, r[now], c[now]});
}

bool rule() {

    node now = *s.begin();
    if (now.r <= 1) {
        printf("%d\n", now.u);
        del(now.u);

        for (int v:G[now.u]) {
            if (dl[v])continue;
            del(v);
        }

        return 1;
    }
    return 0;
}

void go() {
    del((*ss.begin()).u);
}


int main() {
    freopen("set.in", "r", stdin);
//    freopen("C:\\Users\\yanli\\Desktop\\ccsp\\data\\set\\set6.in", "r", stdin);
    freopen("set.out", "w", stdout);
    n = init();
    m = init();
    int u, v;
    for (int i = 1; i <= m; i++) {
        u = init();
        v = init();
        G[u].push_back(v);
        G[v].push_back(u);
        r[v]++;
        r[u]++;
    }
    for (int u = 1; u <= n; u++)
        if (r[u] == 2) {
            for (int v:G[u])c[v]++;
        }
    for (int i = 1; i <= n; i++) {
        s.insert(node{i, r[i]});
        ss.insert(Node{i, r[i], c[i]});
    }

    for (int i = 1; i <= n && s.size(); i++) {
        while (!rule())go();
    }
    return 0;
}

T3 T4 T5 待做

Up一下T3

首先想到算法优化 HWNN降到HWN,然后套一个多线程。看std还用了指令向量优化,好快啊。

赛后

啊济南打铁王

先说一下题目质量还是很不错,很多新颖的题目也比较好玩。

开场先浏览了一下题面,似乎没有很明显的多线程的题。

A题过了之后,B题花了一些时间,午饭后过了。

然后看榜,C题没什么动静(其实后来才知道大家都在努力写),D题有些人得了些分。读完题面,哇,优化题,os学过似乎,先来先服务、时间片轮转什么的,好!稳一点,先写个FIFO试试水。

然后卒,最后不知怎么的那个5分,转战第五题

这题我觉得我太搞笑了。题面读的有点草,什么图形化巴拉巴拉大概就是帮助理解流水线什么的吧,我就直接上手把。amulb直接写了一句汇编之后过了。发现和x86的指令集差别挺大,但是好像和arm指令集有点像,还给了手册。emmmm 当时觉得读读手册,找找跳转指令什么的把fib过了应该不成问题。

然后手册读完了感觉还是不太会用,里面例子很少。无聊翻翻优盘,发现了计算机系统的PPT!“arm基础指令.pptx”!!!!哇,稳了啊,优盘牛逼!!

“对不起,无法打开该文件”。。。。。。

咳咳咳,我投降,吃饭饭

吃完晚饭,哇这C题怎么都过穿了啊,赶紧做。

先写49分稳一点。

好,下面写写两个表的,还有2个小时,最起码再拿23分稳住金。

写写写 49 49 49 20:30+

哇不应该啊 卧槽这xxx . xxx是个什么玩意 哇这他么 改改改

最后没改完投降了

果然银牌第一页,哎 还是计算机系统的基础知识不太够 还有题目读的不太仔细

(赛后问:“哇你们怎么那么厉害,排序的汇编都能自己写出来” “嗯?他不是给了gcc到汇编的指令了吗” “??????”)