20260704 期末考试?总结

题目不难啊,为什么没 AK 呢?

C 罚时总结:题目说了时从前到后排序,第二种情况不要反转。

I 罚时总结:呃?存代码用的。

A - ORXOR

tag:DFS,二进制。

首先二进制枚举断点,然后统计答案。

#include <bits/stdc++.h>

using namespace std;

#define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 20 + 7;
constexpr int P = 998244353;

int n, a[N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    int ans = inf;
    for (int S = 0; S < (1 << n); S++) {
        int o = 0, x = 0;
        for (int i = 1; i <= n; i++) {
            if (S & (1 << (i - 1))) {
                x ^= o;
                o = 0;
            }
            o |= a[i];
        }
        x ^= o;
        ans = min(ans, x);
    }
    printf("%d\n", ans);
    return 0;
}

B - Typical Stairs

tag:DP,加法原理

如果没有坏台阶的限制,就是一个简单的 Fibonacci 数列。

然后如果有限制,不访问就好了。

#include <bits/stdc++.h>

using namespace std;

// #define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 1e5 + 7;
constexpr int P = 1e9 + 7;

int n, m, a[N];
bool b[N];
ll dp[N];

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) scanf("%d", &a[i]), b[a[i]] = true;
    dp[0] = 1, dp[1] = !b[1];
    for (int i = 2; i <= n; i++) {
        if (b[i]) continue;
        debug(i);
        dp[i] = (dp[i - 1] + dp[i - 2]) % P;
    }
    printf("%lld\n", dp[n]);
    return 0;
}

C - Tenzing and Books

tag:贪心,模拟,二进制

直接模拟这个过程,判断能不能选就好了。

#include <bits/stdc++.h>

using namespace std;

#define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 1e5 + 7;
constexpr int P = 998244353;

int n, x;
vector<int> a[4];

void solve() {
    scanf("%d%d", &n, &x);
    for (int i = 1; i <= 3; i++) {
        a[i].resize(n);
        for (auto &j : a[i]) scanf("%d", &j);
        reverse(all(a[i]));
    }
    int u = 0;
    while (!a[1].empty() || !a[2].empty() || !a[3].empty()) {
        bool ok = false;
        for (int i = 1; i <= 3; i++) {
            if (!a[i].empty()) {
                int bk = a[i].back(), zs = bk | u;
                if ((zs | x) == x) {
                    u = zs;
                    a[i].pop_back();
                    ok = true;
                }
            }
        }
        if (!ok) break;
    }
    puts(u == x ? "Yes" : "No");
}

int main() {
    int oT_To = 1;
    scanf("%d", &oT_To);
    while (oT_To--) solve();
    return 0;
}

D - 01迷宫

tag:DFS,tarjan

我们发现,一个联通块的点总是可以互相到达的,然后记录连通块就没了。

#include <bits/stdc++.h>

using namespace std;

// #define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 1000 + 7;
constexpr int P = 998244353;

constexpr int dx[] = {-1, 0, 0, 1};
constexpr int dy[] = {0, -1, 1, 0};

int n, m;
char s[N][N];

bool vis[N][N];
int bel[N][N], nums[N * N];
int siz, p;

char nxt(char ch) {
    return (ch == '1') ? '0' : '1';
}

inline void dfs(int x, int y) {
    if (vis[x][y]) return;
    vis[x][y] = true;
    bel[x][y] = p;
    siz++;
    for (int i = 0; i < 4; i++) {
        int xx = x + dx[i];
        int yy = y + dy[i];
        if (xx < 1 || xx > n || yy < 1 || yy > n) continue;
        debug(xx);
        if (nxt(s[x][y]) == s[xx][yy])
            dfs(xx, yy);
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) {
        scanf("%s", s[i] + 1);
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (!vis[i][j]) {
                siz = 0, ++p;
                dfs(i, j);
                nums[p] = siz;
            }
        }
    }
    while (m--) {
        int u, v;
        scanf("%d%d", &u, &v);
        printf("%d\n", nums[bel[u][v]]);
    }
    return 0;
}


E - Military Problem

tag:dfs 序,DFS。

我们发现子树的 DFN 是连续的,然后没了。

#include <bits/stdc++.h>

using namespace std;

#define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 2e5 + 7;
constexpr int P = 998244353;

int n, q;
vector<int> adj[N];

int dfn[N], id[N], r[N], idx;

inline void dfs(int u, int from) {
    dfn[u] = ++idx;
    id[idx] = u;
    for (auto v : adj[u]) {
        if (v == from) continue;
        dfs(v, u);
    }
    r[u] = idx;
}

int main() {
    scanf("%d%d", &n, &q);
    for (int i = 2; i <= n; i++) {
        int f;
        scanf("%d", &f);
        adj[f].push_back(i);
        adj[i].push_back(f);
    }
    for (int i = 1; i <= n; i++) sort(all(adj[i]));
    dfs(1, 0);
    while (q--) {
        int u, k;
        scanf("%d%d", &u, &k);
        int lid = dfn[u];
        if (lid + k - 1 > r[u]) puts("-1");
        else printf("%d\n", id[lid + k - 1]);
    }
    return 0;
}

F - Transportation

tag:分类讨论,MST。

分情况讨论。

  • 啥都不建
  • 只建机场
  • 只建港口
  • 都建

分别建图,然后跑 MST,建议封装。

#include <bits/stdc++.h>

using namespace std;

#define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 2e5 + 7;
constexpr int P = 998244353;

int n, m, x[N], y[N], fa[N];
vector<array<int, 3>> vec, vc;

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

bool unite(int x, int y) {
    x = find(x), y = find(y);
    if (x == y) return false;
    fa[y] = x;
    return true;
}

ll kruskal(int maxn) {
    for (int i = 1; i <= maxn; i++) fa[i] = i;
    sort(all(vc));
    ll ans = 0;
    for (auto [w, u, v] : vc) {
        if (unite(u, v)) {
            ans += w;
        }
    }
    for (int i = 1; i <= n; i++) if (find(1) != find(i)) return 0;
    return ans;
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &x[i]);
    for (int i = 1; i <= n; i++) scanf("%d", &y[i]);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        vec.push_back({w, u, v});
    }
    ll ans = lnf, mst = 0;
    // only build road
    vc = vec;
    mst = kruskal(n);
    if (mst)
        ans = min(ans, mst);
    // only build airport
    vc = vec;
    for (int i = 1; i <= n; i++) vc.push_back({x[i], i, n + 1});
    mst = kruskal(n + 1);
    if (mst)
        ans = min(ans, mst);
    // only build gangkou
    vc = vec;
    for (int i = 1; i <= n; i++) vc.push_back({y[i], i, n + 2});
    mst = kruskal(n + 2);
    if (mst)
        ans = min(ans, mst);
    // airport & gangkou
    vc = vec;
    for (int i = 1; i <= n; i++) vc.push_back({x[i], i, n + 1});
    for (int i = 1; i <= n; i++) vc.push_back({y[i], i, n + 2});
    mst = kruskal(n + 2);
    if (mst)
        ans = min(ans, mst);
    printf("%lld\n", ans);
    return 0;
}

PS:港口的英文是什么啊!

G - Choosing Capital for Treeland

tag:树形DP(换根)

首先跑 DFS,然后直接反转一次即可。

#include <bits/stdc++.h>

using namespace std;

// #define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 2e5 + 7;
constexpr int P = 998244353;

int n;
ll f[N], g[N], siz[N], k[N], l[N];
vector<int> adj[N];
map<array<int, 2>, bool> edge;

inline void dfs1(int u, int from) {
    siz[u] = 1;
    for (auto v : adj[u]) {
        if (v == from) continue;
        dfs1(v, u);
        f[u] += f[v] + !edge.count({u, v});
        siz[u] += siz[v];
    }
}

inline void dfs2(int u, int from) {
    debug(u);
    for (auto v : adj[u]) {
        if (v == from) continue;
        g[v] += g[u] + (edge.count({v, u}) ? -1 : 1);
        dfs2(v, u);
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        adj[u].push_back(v);
        adj[v].push_back(u);
        edge[{u, v}] = true;
    }
    dfs1(1, 0);
    g[1] = f[1];
    dfs2(1, 0);
    for (int i = 1; i <= n; i++) debug(f[i]);
    for (int i = 1; i <= n; i++) debug(k[i]);
    for (int i = 1; i <= n; i++) debug(l[i]);
    for (int i = 1; i <= n; i++) debug(g[i]);
    int minv = *min_element(g + 1, g + n + 1);
    printf("%d\n", minv);
    for (int i = 1; i <= n; i++) if (g[i] == minv) printf("%d ", i);
    return 0;
}

H - Fox And Jumping

tag:裴蜀定理,EXGCD?,DP,Dijkstra。

如果 \(0\) 能到 \(1\)\(1\) 就一定能到 \(2\),以此类推。

所以,题目就转化成了不定方程问题,充要条件是 \(\gcd = 1\)

然后就用 Dijkstra 求解即可。

#include <bits/stdc++.h>

using namespace std;

// #define AKCoder

#ifdef AKCoder
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'
#else
#define debug(x);
#endif

#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 300 + 7;
constexpr int P = 998244353;

int n, l[N], c[N];

map<int, ll> dis, vis;

void dijkstra(int s) {
    priority_queue<PII, vector<PII>, greater<PII>> q;
    dis[s] = 0;
    q.push({0, s});
    while (!q.empty()) {
        int u = q.top().second;
        q.pop();
        if (vis.count(u)) continue;
        vis[u] = true;
        for (int j = 1; j <= n; j++) {
            int w = c[j], v = gcd(u, l[j]);
            debug(w);
            if (!dis.count(v)) dis[v] = lnf;
            if (dis[u] + w < dis[v]) {
                dis[v] = dis[u] + w;
                q.push({dis[v], v});
            }
        }
    }
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d", &l[i]);
    for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
    dijkstra(0);
    debug(dis[1]);
    if (!dis.count(1)) {
        puts("-1");
        return 0;
    }
    printf("%lld\n", dis[1]);
    return 0;
}

I - Reducing Delivery Cost

艹,没调出来;想到了思路,结果没调试出来,QAQ,替换边的思想应该很显然吧,循环的 sum 没清空,痛失 rk 4,debug 能力要加强啊。

tag:Dijkstra,替换边思想。

首先先全源最短路,然后枚举边,记录答案即可。

#include <bits/stdc++.h>  
  
using namespace std;  
  
// #define AKCoder  
  
#ifdef AKCoder  
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}  
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'  
#else  
#define debug(x);  
#endif  
  
#define ll long long  
#define ull unsigned long long  
#define db double  
#define all(x) (x).begin(), (x).end()  
#define inf (1 << 30)  
#define lnf (1LL << 60)  
typedef pair<ll, int> PII;  
constexpr int N = 1000 + 7;  
constexpr int P = 998244353;  
  
int n, m, k;  
vector<PII> adj[N];  
ll dis[N], d[N][N];  
bool vis[N];  
  
void dijkstra(int s) {  
    priority_queue<PII, vector<PII>, greater<PII>> q;  
    memset(dis, 0x3f, sizeof(dis));  
    memset(vis, false, sizeof(vis));  
    dis[s] = 0;  
    q.push({0, s});  
    while (!q.empty()) {  
        int u = q.top().second;  
        q.pop();  
        if (vis[u]) continue;  
        vis[u] = true;  
        for (auto [v, w] : adj[u]) {  
            if (dis[u] + w < dis[v]) {  
                dis[v] = dis[u] + w;  
                q.push({dis[v], v});  
            }  
        }  
    }  
}  
  
int main() {  
    scanf("%d%d%d", &n, &m, &k);  
    for (int i = 1; i <= m; i++) {  
        int u, v, w;  
        scanf("%d%d%d", &u, &v, &w);  
        adj[u].push_back({v, w});  
        adj[v].push_back({u, w});  
    }  
    for (int i = 1; i <= n; i++) {  
        dijkstra(i);  
        for (int j = 1; j <= n; j++) d[i][j] = dis[j];  
    }  
    vector<array<int, 2>> q;  
    for (int i = 1; i <= k; i++) {  
        array<int, 2> qx;  
        scanf("%d%d", &qx[0], &qx[1]);  
        q.push_back(qx);  
    }  
    for (int i = 1; i <= n; i++) {  
        for (int j = 1; j <= n; j++) {  
            debug(make_pair(i, j));  
            debug(d[i][j]);  
        }  
    }  
    ll ans = lnf;  
    for (int i = 1; i <= n; i++) {  
        for (auto [v, w] : adj[i]) {  
            ll sum = 0;  
            debug(make_pair(i, v));  
            for (auto [qx, qy] : q) {  
                ll qans = min({d[qx][qy], d[qx][i] + d[v][qy], d[qx][v] + d[i][qy]});  
                sum += qans;  
            }  
            debug(sum);  
            ans = min(ans, sum);  
        }  
    }  
    printf("%lld\n", ans);  
    return 0;  
}

J - Kaavi and Magic Spell

又没调出来,记忆化是什么?好吃吗?下次我写记忆化我是 数据删除

tag:区间 DP

首先先补齐位置,比如用 \(114514917831415926\) 填充。

然后设 \(dp_i,_j\)\(t_i \sim t_j\) 匹配 \(s_1 \sim s_{j-i+1}\) 的方案数。

然后可以从两个端点转移,比较可以写个 check。

然后答案就是后面任意选。

#include <bits/stdc++.h>  
  
using namespace std;  
  
#define AKCoder  
  
#ifdef AKCoder  
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}  
#define debug(x) cout<<#x<<" = "<<(x)<<'\n'  
#else  
#define debug(x);  
#endif  
  
#define ll long long  
#define ull unsigned long long  
#define db double  
#define all(x) (x).begin(), (x).end()  
#define inf (1 << 30)  
#define lnf (1LL << 60)  
typedef pair<int, int> PII;  
constexpr int N = 3000 + 7;  
constexpr int P = 998244353;  
  
const char *str = "114514917831415926";  
constexpr int strsize = 18;  
  
char S[N], T[N];  
  
ll dp[N][N];  
  
int main() {  
    scanf("%s", S + 1);  
    scanf("%s", T + 1);  
    int n = strlen(S + 1), m = strlen(T + 1);  
    for (int i = m + 1; i <= n; i++) T[i] = str[i % strsize];  
    auto check = [&](char a, char b) -> char {  
        if (isdigit(b)) return true;  
        return a == b;  
    };  
    for (int i = 1; i <= n; i++) if (check(S[1], T[i])) dp[i][i] = 2;  
    for (int d = 1; d <= n; d++) {  
        for (int i = 1; i + d - 1 <= n; i++) {  
            int j = i + d - 1;  
            if (check(S[d], T[i])) {  
                dp[i][j] = (dp[i][j] + dp[i + 1][j]) % P;  
            }  
            if (check(S[d], T[j])) {  
                dp[i][j] = (dp[i][j] + dp[i][j - 1]) % P;  
            }  
        }  
    }  
    ll ans = 0;  
    for (int i = m; i <= n; i++) {  
        ans = (ans + dp[1][i]) % P;  
    }  
    printf("%lld\n", ans);  
    return 0;  
}

总结

debug 爽了啊。

下次代码写好一点 QAQ。

posted @ 2026-07-05 18:52  AKCoder  阅读(9)  评论(0)    收藏  举报