2020ICPC南京区域赛 补题 & 总结

前言

第一次打线上 ICPC \text{ICPC} ICPC ,记录一下。听说鸭血粉丝汤很好吃,虽然我没吃到,衣服也不赖。比赛环境方面,由于使用自己的设备,还是比较舒服的。

不晓得怎么,一到正式赛,前期脑子就犯懵,基本没有办法快速想出做法,现在觉得可能是平时训练出榜比较快,直接跟榜的缘故吧,正式赛前期榜单还是不太明显的,所以前期缺乏开题自信。另一个原因可能是疏于训练吧,正式赛前除了每周次的常规训练,其他题目倒是没怎么写了,而比赛当周还是考试周。

回顾了一下,前期 zzy \text{zzy} zzy 大力开签到 K \text{K} K 题,差点一血,但是后面 L \text{L} L 题写了相对复杂的扫描线做法,卡了比较久跳了题。期间 xbx \text{xbx} xbx 上机写 E \text{E} E 题,但是也是比较麻烦的分类讨论写法,我则是帮忙看了看卡的 L \text{L} L 题代码,但是没有发现问题(看榜单是签到题,应该直接接手重构的)。之后 zzy \text{zzy} zzy 秒了 F \text{F} F ,直接喂给我打,很快过了,接着 xbx \text{xbx} xbx 也过了 E \text{E} E 题。之后我跟 zzy \text{zzy} zzy 交流了下 M \text{M} M 题,确定树上背包做法后上机,但是打打调调到 3h \text{3h} 3h 才过,期间 xbx \text{xbx} xbx 重构 L \text{L} L 题过了。 zzy \text{zzy} zzy 接过键盘也很快过了 H \text{H} H 题。 3.5h \text{3.5h} 3.5h 的时候 6 6 6 题,但是罚时由于全员前期拉跨直接垮掉。这时候我在 D \text{D} D 题和 J \text{J} J 题反复横跳,直到 4h \text{4h} 4h 的时候 zzy \text{zzy} zzy 点醒了 J \text{J} J 题的最后一个结论,我接手打 J \text{J} J 题,他们则在纸上构造 A \text{A} A 题。最后由于判断失误,我误以为用 segment tree beats \text{segment tree beats} segment tree beats 可能会 TLE \text{TLE} TLE,敲了一个自以为等价的可能小常的势能线段树做法,遂 WA \text{WA} WA 穿。

最后 6 6 6 题罚时炸裂 rk43 \text{rk43} rk43 6 6 6 题从 rk18 \text{rk18} rk18 排到 rk47 \text{rk47} rk47,如果前期没卡太久或者后期决策正确,应该是稳金的吧,可惜没如果。自诩数据结构选手却没写对 J \text{J} J 题,也是挺遗憾的,而且是做法对了、做法会打的情况下。

终归是前期没信心快速签到,回顾几场正式赛,前 1h \text{1h} 1h 我几乎是处于读题状态,很难说精准秒题,即便是签到题?赛后还是多开了几场 cf \text{cf} cf 来练了练手感,为了一周后的济南站准备。

题目链接

https://ac.nowcoder.com/acm/contest/10272

参考题解

A - Ah, It’s Yesterday Once More

简要题意:

对于给定的 n × m n \times m n×m 的方格, 0 0 0 代表障碍, 1 1 1 代表袋鼠。有一串随机生成的长为 5 × 1 0 4 5 \times 10^4 5×104 的指令,仅包含 LRUD \text{LRUD} LRUD 字符,分别表示将所有袋鼠同时向某个方向移动(若能移动,即不经过障碍、不超出方格范围)。现要求构造一个 n × m n \times m n×m 方格图,使得对于随机生成的 500 500 500 串指令,至少有 125 125 125 个满足执行后,所有袋鼠不都在同一个方格。要求构造的袋鼠方格连通、且不含环。

1 ≤ n , m ≤ 20 1 \le n, m \le 20 1n,m20

解题思路:

构造尽可能长且不对称的路径让袋鼠移动,还有就是构造一些分岔路口。可以构造一条沿对角线方向的 Z \text{Z} Z 形路径。

参考代码:
#include<bits/stdc++.h>
using namespace std;

int main(){
   
 
    ios::sync_with_stdio(0); cin.tie(0);
    char ans[21][21] = {
   
    "20 20",
    "11011111011111011111",
    "10110100110100110100",
    "11101101101101101101",
    "10011011011011011001",
    "10110110110110110111",
    "01101101101101101101",
    "11011011011011011011",
    "10110110110110110110",
    "11101101101101101101",
    "10011011011011011001",
    "10110110110110110111",
    "01101101101101101101",
    "11011011011011011011",
    "10110110110110110110",
    "11101101101101101101",
    "10011011011011011001",
    "10110110110110110111",
    "01101101101101101101",
    "01011001011001011001",
    "11110111110111110111",
    };
    for(int i = 0; i <= 20; ++i){
   

        cout << ans[i] << endl;
    }
    return 0;
}

 
附上顺手写的 checker \text{checker} checker,检验袋鼠方格是否连通、无环,输出值为 500 500 500 组随机指令中通过的组数。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;

const int xp[] = {
   0, 0, -1, 1};
const int yp[] = {
   -1, 1, 0, 0};
char ss[23][23];
pii pre[23][23];
int a[23][23], b[23][23], siz[23][23];
int n, m;
mt19937 rnd(time(0));

void mov(int d){
   

    memset(b, 0, sizeof b);
    for(int i = 1; i <= n; ++i){
   

        for(int j = 1; j <= m; ++j){
   

            if(!a[i][j]) continue;
            int x = i + xp[d], y = j + yp[d];
            if(x < 1 || x > n || y < 1 || y > m || ss[x][y] == '0') x = i, y = j;
            if(a[i][j]) b[x][y] += a[i][j];
        }
    }
    memcpy(a, b, sizeof b);
}

int check(){
   

    int ret = 0;
    for(int i = 1; i <= n; ++i){
   

        for(int j = 1; j <= m; ++j){
   

            if(a[i][j]) ++ret;
        }
    }
    return ret > 1;
}

int isHack(){
   

    for(int i = 1; i <= n; ++i){
   

        for(int j = 1; j <= m; ++j) a[i][j] = ss[i][j] - '0';
    }
    for(int i = 1; i <= 50000; ++i){
   

        mov(rnd() % 4);
    }
    return check();
}

pii fin(pii x){
   

    auto &fx = pre[x.first][x.second];
    return x == fx ? x : fx = fin(fx);
}

int unite(pii x, pii y){
   

    auto fx = fin(x), fy = fin(y);
    if(fx == fy) return 0;
    pre[fx.first][fx.second] = fy;
    siz[fy.first][fy.second] += siz[fx.first][fx.second];
    return 1;
}

int isValid(){
   

    int tot = 0, x = 0, y = 0;
    for(int i = 1; i <= n; ++i){
   

        for(int j = 1; j <= m; ++j){
   

            pre[i][j] = pii{
   i, j};
            siz[i][j] = 1;
            if(ss[i][j] == '1') ++tot, x = i, y = j;
        }
    }
    if(!x) return 0;
    for(int i = 1; i <= n; ++i){
   

        for(int j = 1; j <= m; ++j){
   

            if(ss[i][j] != '1') continue;
            if(i > 1 && ss[i - 1][j] == '1'){
   

                if(!unite(pii{
   i - 1, j}, pii{
   i, j})) return 0;
            }
            if(j > 1 && ss[i][j - 1] == '1'){
   

                if(!unite(pii{
   i, j - 1}, pii{
   i, j})) return 0;
            }
        }
    }
    auto fx = fin(pii{
   x, y});
    return siz[fx.first][fx.second] == tot;
}

int main(){
   
 
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= n; ++i){
   

        cin >> ss[i] + 1;
    }
    if(!isValid()){
   

        cout << "0" << endl;
        return 0;
    }
    int ret = 0;
    for(int i = 1; i <= 500; ++i){
   

        if(isHack()) ++ret;
    }
    cout << ret << endl;
    return 0;
}

B - Baby’s First Suffix Array Problem

咕。

C - Certain Scientific Railgun

咕咕。

D - Degree of Spanning Tree

简要题意:

给定一个 n n n 个顶点、 m m m 条边的无向图,保证图连通,可能含有自环和重边。判断是否存在一棵生成树使得没有顶点的度数大于 n 2 \cfrac{n}{2} 2n ,存在则输出任意方案。

多组数据, 2 ≤ n ≤ 1 0 5 , n − 1 ≤ m ≤ 2 × 1 0 5 , ∑ n i ≤ 5 × 1 0 5 , ∑ m i ≤ 1 0 6 2 \le n \le 10^5, n - 1 \le m \le 2 \times 10^5, \sum n_i \le 5 \times 10^5, \sum m_i \le 10^6 2n105,n1m2×105,ni5×105,mi106

解题思路:

对于 n n n 个顶点的树,用 d ( i ) d(i) d(i) 表示顶点 i i i 的度数,对任意两个顶点 u , v u, v u,v,有 d ( u ) + d ( v ) ≤ n d(u) + d(v) \le n d(u)+d(v)n,取等号当且仅当 u , v u, v u,v 邻接。故任意取一棵生成树,度数大于 n 2 \cfrac{n}{2} 2n 的顶点最多只有一个,若没有这样的点,则输出答案。否则将其设为根 r t rt rt 并试图调整其度数。接下来遍历其他所有边,若边 e ( u , v ) e(u, v) e(u,v) 能替换 r t rt rt 邻接的一条边,则替换,直到 d ( r t ) = ⌊ n 2 ⌋ d(rt) = \lfloor\cfrac{n}{2}\rfloor d(rt)=2n

注意到这个过程可能让某个顶点 u u u 的度数大于 n 2 \cfrac{n}{2} 2n,这样的 u u u 只可能是 r t rt rt 的邻接点,因为当 d ( r t ) = ⌊ n 2 ⌋ d(rt) = \lfloor\cfrac{n}{2}\rfloor d(rt)=2n 时, d ( u ) + d ( r t ) = ( ⌊ n 2 ⌋ + 1 ) + ⌊ n 2 ⌋ ≥ n d(u) + d(rt) = (\lfloor\cfrac{n}{2}\rfloor + 1) + \lfloor\cfrac{n}{2}\rfloor \ge n d(u)+d(rt)=(2n+1)+2nn ,上面提到若两顶点不邻接,度数和将小于 n n n

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值