2025天梯赛校内第二场排位赛

这一次的排位赛比较简单,所以只挑了 7-8 和 7-12

7-8

\(\qquad\) 2014 年哈佛-麻省理工数学竞赛中一道题是这样的:将正整数 1, 2, ..., 64 填入 8×8 的方格棋盘中,使得对任何 1≤i<64,i 和 i+1 都必须填在两个具有公共边的方格中。求棋盘上对角线中所填数的和的最大值。(注意:两个对角线都要考虑;64 和1 也必须填在两个具有公共边的方格中。)
\(\qquad\) 这题有点难…… 幸好我们并不要求你写程序解决这个问题。
\(\qquad\) 你的任务是:对任一给定的数字填充方案,判定其是否满足填充的条件,并且在所有给出的方案中,找出满足条件的、且对角线数字和最大的那个方案。

\(\qquad\) 对于这一道题,我们可以选择用模拟的方式,只需要枚举每一个 i 的上下左右四个偏移量看是否存在 i+1 即可,值得注意的是,对于 n*n 我们需要寻找的是四个偏移量中是否存在 1.
\(\qquad\) 然后就是这道题最大的一个毒点,测试点 2,19分的应该基本上都是WA在这里了。这一个测试点的要求为,当不存在符合要求的矩阵时,不仅要输出0,还要输出两个换行。

#include <bits/stdc++.h>

using namespace std;

#define pii pair<int, int>
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

int main(){
    int n, m;
    cin >> n >> m;
    priority_queue<pii> q;
    //bool vis[n+1][n+1];
    vector<vector<int>> g(n+1, vector<int>(n+1));
    int cnt = 0;
    while(m--){
        cnt++;
        //memset(vis, 0, sizeof(vis));
        for(int i = 1; i <= n; i ++ ){
            for(int j = 1; j <= n; j ++ ){
                cin >> g[i][j];
            }
        }
        bool fg = 1;
        for(int i = 1; i <= n; i ++ ){
            for(int j = 1; j <= n; j ++ ){
                int s = 0;
                // if(g[i][j] == n*n) continue;
                // for(int k = 0; k < 4; k ++ ){
                //     int nx = i + dx[k], ny = j + dy[k];
                //     if(nx < 1 || nx > n || ny < 1 || ny > n) continue;
                //     if(g[nx][ny] == g[i][j] + 1) s++;
                // }
                if(g[i][j] == n*n){
                    for(int k = 0; k < 4; k ++ ){
                        int nx = i + dx[k], ny = j + dy[k];
                        if(nx < 1 || nx > n || ny < 1 || ny > n) continue;
                        if(g[nx][ny] == 1) s++;
                    }
                } else {
                    for(int k = 0; k < 4; k ++ ){
                        int nx = i + dx[k], ny = j + dy[k];
                        if(nx < 1 || nx > n || ny < 1 || ny > n) continue;
                        if(g[nx][ny] == g[i][j] + 1) s++;
                    }
                }
                if(!s) fg = 0;
            }
        }
        if(!fg) continue;
        int ans1 = 0, ans2 = 0;
        for(int i = 1; i <= n; i ++ ) ans1 += g[i][i];
        for(int i = n, j = 1; i >= 1; i -- , j ++ ) ans2 += g[j][i];
        int ans = max(ans1, ans2);
        q.push({ans, cnt});
    }
    // while(q.size()){
    //     auto t = q.top();q.pop();
    //     cout << t.second << ' ';
    // }
    // cout << q.size() << endl;
    if(q.empty()){cout << 0 << endl; cout << endl; return 0;} //没有符合要求的要输出两个换行
    int maxx = q.top().first;
    int ans = 0;
    vector<int> res;
    while(q.size() && q.top().first == maxx){
        ans ++;
        auto t = q.top(); q.pop();
        res.push_back(t.second);
    }
    cout << ans << endl;
    sort(res.begin(), res.end());
    for(int i = 0; i < res.size(); i ++ ){
        if(i == 0) cout << res[i];
        else cout << ' ' << res[i];
    }
}

7-12

\(\qquad\) This time let us consider the situation in the movie "Live and Let Die" in which James Bond, the world's most famous spy, was captured by a group of drug dealers. He was sent to a small piece of land at the center of a lake filled with crocodiles. There he performed the most daring action to escape -- he jumped onto the head of the nearest crocodile! Before the animal realized what was happening, James jumped again onto the next big head... Finally he reached the bank before the last crocodile could bite him (actually the stunt man was caught by the big mouth and barely escaped with his extra thick boot).
\(\qquad\) Assume that the lake is a 100 by 100 square one. Assume that the center of the lake is at (0,0) and the northeast corner at (50,50). The central island is a disk centered at (0,0) with the diameter of 15. A number of crocodiles are in the lake at various positions. Given the coordinates of each crocodile and the distance that James could jump, you must tell him whether or not he can escape.

译文(赛后给出版本):
\(\qquad\) 以下是DeepSeek的翻译,仅供读题参考:
这次让我们考虑电影《生死关头》中的场景:世界著名特工詹姆斯·邦德被毒贩集团抓获,他被困在鳄鱼池中央的小岛上。他完成了最惊险的逃脱动作——跳上了最近的鳄鱼头部!在鳄鱼反应过来之前,詹姆斯又跳向了下一个鳄鱼头... 最终他在最后一只鳄鱼咬到他之前成功上岸(实际上特技演员曾被鳄鱼大口咬住,靠着加厚靴子勉强逃脱)。
\(\qquad\)假设湖泊是一个100×100的正方形区域,中心位于坐标(0,0),东北角坐标为(50,50)。中心岛是一个以(0,0)为圆心,直径为15的圆形区域。湖中有若干鳄鱼分布在各个位置。给定每条鳄鱼的坐标和詹姆斯能跳跃的最大距离,请判断他是否能成功逃脱。

\(\qquad\) 由于这一道题的输出只有"Yes"或"No",所以是可以骗分的,骗到 25 分也不是不行,但是这里还是讲一下正解。这道题可以用 bfs 或者 dfs 来做。我写的是 dfs 的方法。
\(\qquad\) 首先看题目,简化一下意思就是,007在中心为(0,0)半径为7.5的岛屿上出发,落脚点是若干个鳄鱼,并且给出最大跳跃距离 D ,询问是否有一条路径可以让他跳出边界
\(\qquad\) 不难看出搜索是在 D,与每一个鳄鱼的坐标的基础上进行的。而题目中并没有给出 D 的范围,因此直接从中心岛跳出边界的情况也是存在的,所以可以对其进行一个特判。
\(\qquad\) 接着,我们要找到第一个可以跳上的鳄鱼的坐标,因为岛的半径为7.5,所以第一个能跳上的坐标应满足 \(x*x+y*y-7.5 ≤ D\).
\(\qquad\) 然后就可以从第一个点开始对路径进行深度优先搜索,查找是否存在一条路径可以使007跳出边界。

#include <bits/stdc++.h>

using namespace std;

const int N = 110;
double n, d;

struct Crocodiles{
    double x, y;
}crocodiles[N];

bool vis[N];

bool check(Crocodiles& c){
    double x = c.x, y = c.y;
    if(x+d >= 50 || y+d >= 50 || x-d <= -50 || y-d <= -50) return true;
    return false;
}

double D(Crocodiles& A, Crocodiles& B){
    return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}

bool dfs(int u){
    vis[u] = 1;
    int ans = check(crocodiles[u]);
    if(!ans){
        for(int i = 1; i <= n; i ++ ){
            if(!vis[i] && D(crocodiles[i], crocodiles[u]) <= d)
                ans = dfs(i);
            if(ans) break;
        }
    }
    return ans;
}

int main(){
    cin >> n >> d;
    if(d >= 43) {cout << "Yes" << endl; return 0;}
    vector<int> fir;
    for(int i = 1; i <= n; i ++ ){
        cin >> crocodiles[i].x >> crocodiles[i].y;
        int x = crocodiles[i].x, y = crocodiles[i].y;
        double dis = sqrt(x*x+y*y)-7.5;
        if(dis < d) fir.push_back(i);
    }
    bool fg = 0;
    for(int i = 0; i < fir.size(); i ++ ){
        fg = dfs(fir[i]);
        if(fg) break;
    }
    if(fg) cout << "Yes" << endl;
    else cout << "No" << endl;
}
posted @ 2025-03-24 16:37  算法蒟蒻沐小白  阅读(46)  评论(2)    收藏  举报