SMU Summer 2024 Contest Round 2(7.9)

A Sierpinski carpet

思路:考虑把每一级的结构存下来,每一级都由3*3个上一级的结构推出的。先推出第一层1*3的结构,后面两层2*3直接复制1*3的结构,再找到中心位置赋值成白色即可

void solve() {
    vector<vector<string> > ve(10, vector<string> (1000, "") );
    ve[1][1] = "###";
    ve[1][2] = "#.#";
    ve[1][3] = "###";
    ve[2][1] = "#########";
    ve[2][2] = "#.##.##.#";
    ve[2][3] = "#########";
    ve[2][4] = "###...###";
    ve[2][5] = "#.#...#.#";
    ve[2][6] = "###...###";
    ve[2][7] = "#########";
    ve[2][8] = "#.##.##.#";
    ve[2][9] = "#########";
    int n;
    cin >> n;
    if (n == 0) {
        cout << "#";
        return ;
    }
    for (int p = 3; p <= n; ++p) {
        for (int i = 1; i <= pow(3, p - 1); ++i) {
            ve[p][i] = ve[p - 1][i] + ve[p - 1][i] + ve[p - 1][i];
        }
        int s = pow(3, p - 1);
        for (int i = 1; i <= pow(3, p - 1); ++i) {
            ve[p][i + s] = ve[p][i];
            ve[p][i + s + s] = ve[p][i];
        }
        for (int i = s + 1; i < s + s + 1; ++i) {
            for (int j = s + 1; j < s + s + 1; ++j) {
                ve[p][i][j - 1] = '.';
            }
        }
    }
    for (int i = 1; i <= pow(3, n); ++i) {
        cout << ve[n][i] << '\n';
    }
}

B Consecutive

思路:先找出哪些位置是合法的,维护前缀和即可(注意不能算上右边界的贡献)

void solve() {
    int n, q;
    cin >> n >> q;
    string s;
    cin >> s;
    s = ' ' + s;
    vector<int> ve(n + 5);
    for (int i = 1; i < n; ++i) {
        if (s[i] == s[i + 1]) ve[i] = 1;
        ve[i] += ve[i - 1];
    }
    for (int i = 0; i < q; ++i) {
        int l, r;
        cin >> l >> r;
        cout << ve[r - 1] - ve[l - 1] << '\n';
    }
}

C Minimum Width

思路:首先应该把题目读清楚(刚开始读假了,顺序是已经定好的,那问题就简单了),二分W,按顺序判断单词是否都能放下即可

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> ve(n + 1);
    for (int i = 1; i <= n; ++i) {
        cin >> ve[i];
    }



//    sort(ve.begin() + 1, ve.end());
    int l = 1, r = 1e15, ans;
    auto check = [=] (int x) {
        int res = 1, now = 0;
        for (int i = 1; i <= n; ++i) {
            if (ve[i] > x) return false;
            if (now == 0) now += ve[i];
            else {
                if (now + ve[i] + 1 <= x) {
                    now += 1 + ve[i];
                } else {
                    res ++;
                    now = ve[i];
                }
            }
        }
        return res <= m;
    };
    while (l <= r) {
        int mid = l + r >> 1;
        if (check(mid)) ans = mid, r = mid - 1;
        else l = mid + 1;
    }
    cout << ans;
}

D Printing Machine

思路:贪心,按时间来考虑,先处理先进到打印机里的文件,若有多个文件,则先处理最先退出打印机的文件

void solve() {
    int n;
    cin >> n;
    vector<PII> ve(n);
    for (int i = 0; i < n; ++i) {
        cin >> ve[i].first >> ve[i].second;
        ve[i].second += ve[i].first;
    }
    sort(ve.begin(), ve.end());
    priority_queue<int, vector<int>, greater<int> > q;
    int res = 0, now = 0, idx = 0;
    while (q.size() || idx < n) {
        while (idx < n && ve[idx].first <= now) {
            q.push(ve[idx++].second);
        }
        if (q.size()) {
            res ++, now ++, q.pop();
        }
        while (q.size() && q.top() < now) q.pop();
        if (q.empty() && idx < n) {
            now = ve[idx].first;
        }
    }
    cout << res;
}

E Nearest Black Vertex

思路:n的范围2e3,分两步:

1.把距离pi距离小于di的点都标为白色,bfs每个pi

2.把距离pi刚好为di的点(非白色)都标为黑色,若某个pi不存在这样的黑点则No,bfs每个pi

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define PII pair<int, int>
//#define double long double
const int N = 2e5 + 5, mod = 1e9 + 7;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<vector<int> > ve(n + 1);
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        ve[u].push_back(v), ve[v].push_back(u);
    }
    int k;
    cin >> k;
    if (k == 0) {
        cout << "Yes\n";
        cout << "1";
        for (int i = 2; i <= n; ++i) cout << "0";
        return ;
    }
    vector<int> col(n + 1), p(k), d(k);
    auto bfs = [&] (int u, int dis) {
        vector<int> vis(n + 1);
        queue<PII> q;
        q.push({u, 0});
        vis[u] = 1;
        while (q.size()) {
            auto t = q.front();
            q.pop();
            if (t.second < dis) col[t.first] = -1;
            if (t.second + 1 < dis) {
                for (auto v:ve[t.first]) {
                    if (vis[v]) continue;
                    vis[v] = 1;
                    q.push({v, t.second + 1});
                }
            }
        }
    };
    for (int i = 0; i < k; ++i) {
        cin >> p[i] >> d[i];
        bfs(p[i], d[i]);
    }
    bool ok = true;
    auto bfs1 = [&] (int u, int dis) {
        bool is = false;
        queue<PII> q;
        vector<int> vis(n + 1);
        q.push({u, 0});
        vis[u] = 1;
        while(q.size()) {
            auto t = q.front();
            q.pop();
            if (t.second == dis) {
                if (col[t.first] == 1) is = true;
                if (col[t.first] != -1) {
                    col[t.first] = 1;
                    is = true;
                }
                continue;
            }
            for (auto v:ve[t.first]) {
                if (vis[v]) continue;
                vis[v] = 1;
                q.push({v, t.second + 1});
            }
        }
        return is;
    };
    for (int i = 0; i < k; ++i) {
        ok = bfs1(p[i], d[i]);
        if (!ok) break;
    }
    if (ok) {
        cout << "Yes\n";
        for (int i = 1; i <= n; ++i) {
            if (col[i] == 1) cout << "1";
            else cout << "0";
        }
    } else cout << "No";
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T = 1;
    while (T --) {
        solve();
    }
    return 0;
}

F Christmas Present 2

思路:可以随时回去补充礼物并按顺序送完,dp做法

f[i]表示,送完1~i并且最后回家的最小路径,考虑从上一次回家补充转移过来:f[i] = min ( f[j] + dis[st -> j+1] + dis[j+1 -> i] + dis[i ->st] ),其中i-k <= j <= i-1

这里dis[j+1 -> i]可以用前缀和求出,即sum[i] - sum[j+1],最后调整下式子,将关于j的放在一边:f[i] = min ( ( f[j] + dis[j+1 -> i] - sum[j+1] )+ sum[i] + dis[i ->st] )

如果枚举j复杂度是n2的,这里从式子可以看出f[j] + dis[j+1 -> i] - sum[j+1] 可以用单点队列维护,这样复杂度就是n的

#include <bits/stdc++.h>

using namespace std;

#define int long long
//#define double long double
#define PII pair<int, int>
#define PDI pair<double, int>

const int N = 2e5 + 5, mod = 1e9 + 7;
struct E{
    double x, y;
};
void solve() {
    int n, k;
    cin >> n >> k;
    vector<E> ve(n + 5);
    auto dis = [] (E a, E b) {
        double d = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
        return (double)sqrt(d);
    };
    for (int i = 0; i <= n; ++i) cin >> ve[i].x >> ve[i].y;
    vector<double> stoi(n + 5), sum(n + 5), f(n + 5);
    for (int i = 1; i <= n; ++i) {
        stoi[i] = dis(ve[0], ve[i]);
        if (i > 1)
        sum[i] = sum[i - 1] + dis(ve[i], ve[i - 1]);
    }

    deque<PDI> q;
    q.push_back({ f[0] + stoi[1] - sum[1], 0});
    for (int i = 1; i <= n; ++i) {
        while (q.size() && q.front().second < i - k) {
            q.pop_front();
        }
        f[i] = q.front().first + sum[i] + stoi[i];
        double d = f[i] + stoi[i + 1] - sum[i + 1];
        while (q.size() && q.back().first >= d) q.pop_back();
        if (i < n) q.push_back({ d, i});
    }
    cout << fixed << setprecision(12) << f[n];
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    int T = 1;
    while (T --) {
        solve();
    }
    return 0;
}

 

posted @ 2024-07-09 14:58  bible_w  阅读(48)  评论(0编辑  收藏  举报