smu2024蓝桥杯训练3

A

思路:维护第一组出现的数即可
查看代码

void solve() {
    int n, m, ans = 0;
    set<int> se;
    cin >> n >> m;
    for (int i = 0, x; i < n; ++i) cin >> x, se.insert(x);
    for (int i = 0, x; i < m; ++i) {
        cin >> x;
        if(se.count(x)) ans ++;
    }
    cout << ans;
}

B

思路:可以看到n的范围并不大,枚举所有人,每满m个单价加v
查看代码
 void solve() {
    int ans = 0, n, v, m, a;
    cin >> n >> v >> m >> a;
    for (int i = 1; i <= n; ++i) {
        ans += v;
        if (i % m == 0) v += a;
    }
    cout << ans;
}

C

思路:求距离可以求出两个数所在的位置,位置差的和即为距离。可以发现奇数行是正序,偶数行是逆序,根据行数再求出列数即可
 
查看代码
 void solve() {
    int w, m, n;
    cin >> w >> m >> n;
    auto P = [w](int x) {
        int h = (x + w - 1) / w, l;
        if (h % 2) {
            l = x % w;
            if (l == 0) l = w;
        } else {
            l = w - x % w + 1;
            if (l == w + 1) l = 1;
        }
        PII ans = {h, l};
        return ans;
    };
    PII a = P(m), b = P(n);
    cout << abs(a.first - b.first) + abs(a.second - b.second);
}

D

思路:由于子串中一种字符只能存在一个,且一个字符在一个子串中的贡献为1。那就统计每个字符带来的贡献,预处理出一个位置的前后再次出现该字符的位置,统计与前后的间隔l和r,这个位置上的字符带来的贡献即为l * r,这样的复杂度是On的
 
查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e4 + 5;
const int dx[4] = {0,-1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f;



void solve() {
    string s;
    cin >> s;
    int n = s.size();
    s = ' ' + s;
    vector<int> vel(n + 5);
    vector<int> ver(n + 5);
    vector<int> pos(30, n + 1);
    for (int i = n; i >= 1; --i) {
        ver[i] = pos[s[i] - 'a'];
        pos[s[i] - 'a'] = i;
    }
    pos = vector<int> (30, 0);
    for (int i = 1; i <= n; ++i) {
        vel[i]= pos[s[i] - 'a'];
        pos[s[i] - 'a'] = i;
    }
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        int a = i - vel[i];
        int b = ver[i] - i;
        ans += a * b;
    }
    cout << ans;
}

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

E

 
思路:dp,之前写过这道啦
根据xxxxx = xxx00 + xx,以这种形式看一个数。对于xx只需要找到符合条件的xxx00(x可以是多位,0的个数为xx的个数)满足%k等于0。
用f[i][j]表示a[ ]*10i % k = j 的数的个数,统计每个数的xxx00个数
 
查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e4 + 5;
const int dx[4] = {0,-1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f;



void solve() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n + 1), cnt(n + 1);
    vector f(10, vector<int> (k));
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
        for (int j = 1, x = a[i]; j <= 9; ++j) {
            x *= 10;
            f[j][x % k] ++;
        }
        int x = a[i], c = 0;
        while (x > 0) {
            c ++;
            x /= 10;
        }
        cnt[i] = c;
    }
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        int c = (k - (a[i] % k)) % k;
        ans += f[cnt[i]][c];
        c = (a[i] + (int)(a[i] * pow(10, cnt[i]))) % k;
        if (c == 0) ans --;
    }
    cout << ans;
}

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

F

 
思路:dp,题目说了要在T内用完M力量,f[i][j]表示在i秒内用了j力量没有死掉的方案数
状态为:第i秒用1力量:f[i][j] += f[i-1][j-1]
             第i秒什么都不做:f[i][j] += f[i-1][j]
这里需要满足D - (i - j)+ j > 0
 
查看代码
 #include<bits/stdc++.h>

using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e4 + 5;
const int dx[4] = {0, -1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f, Mod = 1e9 + 7;


void solve() {
    int D, T, M;
    cin >> D >> T >> M;
    vector f(T + 1, vector<int> (M + 1));
    f[0][0] = 1;
    for (int i = 1; i <= T; ++i) {
        for (int j = 0; j <= min(i, M); ++j) {
            if (D - i + 2 * j <= 0) continue;
            if (j) f[i][j] = (f[i][j] + f[i - 1][j - 1]) % Mod;
            f[i][j] = (f[i][j] + f[i - 1][j]) % Mod;
        }
    }
    cout << f[T][M];
}

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

H

 
思路:dp,首先f[i][j]表示S的前i个包含T的前j个的最少操作次数
若S[i] = T[j],f[i][j] = f[i - 1][j - 1]
若S[i] != T[j], f[i][j] = min (f[i - 1][j - 1] + 1,f[i - 1][j]), 分别表示对S[i]进行修改、不对S[i]操作即S的前i - 1要包含T的前j个
 
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e4 + 5;
const int dx[4] = {0,-1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f;



void solve() {
    string S, T;
    cin >> S >> T;
    int n, m;
    n = S.size(), m = T.size();
    S = ' ' + S, T = ' ' + T;
    vector f(n + 1, vector<int> (m + 1, INF));
    for (int i = 0; i <= n; ++i) f[i][0] = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= i && j <= m; ++j) {
            if (S[i] == T[j]) f[i][j] = f[i - 1][j - 1];
            else f[i][j] = min(f[i - 1][j - 1] + 1, f[i - 1][j]);
        }
    }
    cout << f[n][m];
}

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

I

 
思路:算是暴力过的吧,首先用并查集合并,当添加权值时,对该集合的父亲进行标记,当合并时,首先将所有点先进行权值增加,增加后将父亲的标记清空,再合并
 
 
查看代码
 #include<bits/stdc++.h>

using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e6 + 5;
const int dx[4] = {0, -1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f;


int n, m;
int fa[N];

int find(int x) {
    if (x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}

void mer(int a, int b) {
    a = find(a), b = find(b);
    if (a != b) fa[b] = a;
}


void solve() {
    cin >> n >> m;
    vector<int> ans(n + 1), c(n + 1, 0);
    for (int i = 1; i <= n; ++i) fa[i] = i;
    for (int i = 0; i < m; ++i) {
        int op, a, b;
        cin >> op >> a >> b;
        if (op == 1) {
            if (find(a) != find(b)) {
                for (int i = 1; i <= n; ++i) {
                    ans[i] += c[find(i)];
                }
                fill(c.begin(), c.end(), 0);
                mer(a, b);
            }
        } else {
            c[find(a)] += b;
        }
    }
    for (int i = 1; i <= n; ++i) cout << ans[i] + c[find(i)] << ' ';
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
//    cin >> T;
    while (T--) {
        solve();
    }
}
看了别的解法树上差分+并查集,首先还是再添加权值时,只对父亲进行标记,当合并时,新增一个节点,让两个集合的父亲的父亲都为该新增节点,这样如果再进行添加权值时,不会影响到原先集合的添加权值,最后dfs所有新增节点,往下添加权值
查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e5 + 5;
const int dx[4] = {0,-1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f;

int n, m, idx;
int fa[N], val[N];
int find(int x) {
    if (x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}
vector<vector<int> > ve(N);

void dfs(int u,int v) {
//    int vv = v + val[u];
//    ans[u] += vv;
    val[u] += v;
    for (auto a: ve[u]) {
        dfs(a, val[u]);
    }
}

void solve() {
    cin >> n >> m;
    idx = n + 1;
    for (int i = 1; i <= n; ++i) fa[i] = i;
    for (int i = 0; i < m; ++i) {
        int op, a, b;
        cin >> op >> a >> b;
        if (op == 1) {
            a = find(a), b = find(b);
            if (a != b) {
                fa[a] = idx, fa[b] = idx, fa[idx] = idx;
                ve[idx].push_back(a), ve[idx].push_back(b);
                idx ++;
            }
        } else {
            val[find(a)] += b;
        }
    }
    for (int i = 1; i < idx; ++i)
        if (i == find(i)) dfs(i, 0);
    for (int i = 1; i <= n; ++i) cout << val[i] << ' ';
}

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

J

 
 
思路:啊分层最短路还是做的少,没想到
由于要选两条路出来,那就多建2层图出来,层之间为选的一条路,有3层说明选了两条路,一层内还是按原图的可行路建图,注意层与层之间是单向边,最后跑最短路即可
 
查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
#define PII pair<int, int>
#define PDI pair<double, int>
const double eps = 1e-12;
const int N = 1e4 + 5;
const int dx[4] = {0,-1}, dy[4] = {-1, 0};
const int INF = 0x3f3f3f3f;

struct E{
    int v, w;
};

void solve() {
    int n, m;
    cin >> n >> m;
    vector<vector<E> > ve(3 * n + 5);
    vector<int> dis(3 * n + 5, INF);
    auto add = [&](int a, int b, int c) {
        ve[a].push_back({b, c});
    };
    for (int i = 0; i < m; ++i) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        if (d == 1) {
            add(a, b + n, c), add(b, a + n, c);
            add(a + n, b + 2 * n, c), add(b + n, a + 2 * n, c);
        } else {
            add(a, b, c), add(b, a, c);
            add(a + n, b + n, c), add(b + n, a + n, c);
            add(a + 2 * n, b + 2 * n, c), add(b + 2 * n, a + 2 * n, c);
        }
    }
    dis[1] = 0;
    priority_queue<PII, vector<PII>, greater<PII> > q;
    vector<int> st(3 * n + 5);
    q.push({dis[1], 1});
    while (!q.empty()) {
        auto [d, u] = q.top();
        q.pop();
        if (st[u]) continue;
        st[u] = 1;
        for (auto [v, w]:ve[u]) {
            if (dis[v] > d + w) {
                dis[v] = d + w;
                q.push({dis[v], v});
            }
        }
    }
    cout << dis[n] - min({dis[n], dis[n + n], dis[n + n + n]});
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T = 1;
//    cin >> T;
    while (T--) {
        solve();
    }
}
posted @ 2024-04-09 23:56  bible_w  阅读(13)  评论(0编辑  收藏  举报