2021杭州师范大学acm新生赛题解

看情况更新
cf上的题目链接

warmup - DOMjudge (hznu.edu.cn)

A 最短路

题意:你要从1号城市的学校到\(n\)号城市的比赛场地,每个城市有铁路站和飞机场,铁路站可以到另一个铁路站,飞机场可以到另一个飞机场,构成一个无向图,每条边有\(a\)的路费和\(b\)的时间两种权值。此外,在一个城市内部进行学校,飞机场,铁路站,比赛场地之间的转移会消耗固定的路费\(x\)和时间\(y\),问你从1城市的学校到n城市的比赛场地最少要多少钱,在满足钱最少的前提下最小要多少时间,到不了输出-1.

思路:我们把每个城市的铁路站和飞机场作为两个不同的点,按题意把飞机的路线和铁路的路线连完后再把每一个单个城市内的飞机场和铁路连起来,把起点看作0号点连两条有向边到1号城市的飞机和1号城市的铁路,把终点看作\(2*n+1\)号点,由\(n\)号城市的飞机和铁路连两条有向边到该点。然后跑一次最短路。注意这样建图的话只有一个城市时需要特判。

代码:

// Author: yukito8069
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
typedef long long ll;
typedef long double dd;
typedef pair<int, int> pii;
const int N = 200010;
const int M = 600010;
int n, m, l, x, y;
int h[N], rmb[M], e[M], ne[M], t_m[M], idx;
int trmb[N], ttm[N];
bool st[N];
void add(int a, int b, int my, int time) {
    e[idx] = b, ne[idx] = h[a], t_m[idx] = time, rmb[idx] = my, h[a] = idx++;
}
void dijkstra() {
    priority_queue<pii, vector<pii>, greater<pii>>hp;
    for (int i = 0; i <= n * 2 + 10; i++) {
        trmb[i] = 0x3f3f3f3f;
        ttm[i] = 0x3f3f3f3f;
        st[i] = 0;
    }
    trmb[0] = 0; ttm[0] = 0;
    hp.push({ 0, 0 });
    while (hp.size()) {
        auto tt = hp.top(); hp.pop();
        int ver = tt.second; int cost = tt.first;
        if (st[ver]) continue;
        st[ver] = 1;
        for (int i = h[ver]; i != -1; i = ne[i]) {
            int j = e[i];
            if (trmb[j] > cost + rmb[i]) {
                trmb[j] = cost + rmb[i];
                ttm[j] = ttm[ver] + t_m[i];
                hp.push({trmb[j], j});
            }
            else if (trmb[j] == cost + rmb[i] && ttm[j] > ttm[ver] + t_m[i]) {
                ttm[j] = ttm[ver] + t_m[i];
            }
        }
    }
}
int main() {
    IOS;
    int t; cin >> t;
    while (t--) {
        cin >> n >> m >> l >> x >> y;
        if(n == 1) {
            cout << x << " " << y << "\n";
            continue;
        }
        idx = 0;
        for (int i = 0; i <= 2 * n + 10; i++) {
            h[i] = -1;
        }
        for (int i = 1; i <= m; i++) {
            int u, v, a, b; cin >> u >> v >> a >> b;
            u = u * 2 - 1;
            v = v * 2 - 1;
            add(u, v, a, b); add(v, u, a, b);
        }
        for (int i = 1; i <= l; i++) {
            int u, v, a, b; cin >> u >> v >> a >> b;
            u = u * 2; v = v * 2;
            add(u, v, a, b); add(v, u, a, b);
        }
        for (int i = 1; i <= n; i++) {
            add(2 * i - 1, 2 * i, x, y); add(i * 2, i * 2 - 1, x, y);
        }
        add(0, 1, x, y); add(0, 2, x, y); add(n * 2 - 1, 2 * n + 1, x, y); add(n * 2, 2 * n + 1, x, y);
        dijkstra();
        if(trmb[n * 2 + 1] == 0x3f3f3f3f) {
            cout << -1 << "\n";
            continue;
        }
        cout << trmb[n * 2 + 1] << " " << ttm[n * 2 + 1]<< "\n";
    }
}

B 二分

二分

// Author: yukito8069
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
typedef long long ll;
typedef double dd;
typedef pair<int, int> pii;
int n, m;
int a[1010];
bool cmp(int x, int y) {
    return x > y;
}
bool check(int x) {
    int cnt = 1;
    int dif = 0;
    for (int i = 1; i <= n - 1; i++) {
        dif += a[i + 1] - a[i];
        if(dif >= x) {
            cnt++;
            dif = 0;
        }
    }
    if(cnt >= m) return 1;
    return 0;
}
int main() {
    IOS;
	int T;
	cin >> T;
	while (T--) {
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
        }
        sort(a + 1, a + 1 + n);
        int l = 0, r = a[n], ret = l;
        while(l <= r) {
            int mid = l + r >> 1;
            if(check(mid)) {
                l = mid + 1;
                ret = mid;
            }
            else {
                r = mid - 1;
            }
        }
        cout << ret << "\n";
    }
	return 0;
}

C dp 二进制枚举

题意:你在1号岛,要到n号岛,你有一个数组a,你每次移动时可以挑一个数组中的元素作为移动的距离,你还有一个数组b,你决定挑其中的一些数,把它们也作为移动的距离的选项。q次询问,问你到n号岛有几种方式。

思路:询问次数这么多所以要提前预处理。注意到b数组长度上限为10,想到二进制枚举每一种方案的结果。

// Author: yukito8069
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
typedef long long ll;
typedef double dd;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
int n, m, k;
int a[20];
int b[20];
int f[1 << 19];
int ans[1 << 19];
int main() {
    IOS;
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= k; i++) {
        cin >> b[i];
    }
    for (int i = 0; i < 1 << k; i++) {
        for (int j = 0; j <= n; j++) {
            f[j] = 0;
        }
        f[1] = 1;
        for (int j = 1; j <= n; j++) {//注意这层循环一定要在外面
            for (int z = 1; z <= m; z++) {
                if(j >= a[z])
                    f[j] = (f[j] + f[j - a[z]]) % mod;
            }
            for (int z = 0; z <= 9; z++) {
                if(i & (1 << z)) {
                    if(j >= b[z + 1])
                        f[j] = (f[j] + f[j - b[z + 1]]) % mod;
                }
            }
        }
        ans[i] = f[n];
    }
    int q; cin >> q;
    for (int i = 1; i <= q; i++) {
        int c; cin >> c;
        int cur = 0;
        for (int j = 1; j <= c; j++) {
            int d; cin >> d;
            cur |= (1 << (d - 1));
        }
        cout << ans[cur] << "\n";
    }
}

E 签到

// Author: yukito8069
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
typedef long long ll;
typedef double dd;
typedef pair<int, int> pii;
int a[100010];
int main() {
    IOS;
    int n; cin >> n;
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        if(a[i] % 2 == 0) {
            cnt++;
        }
    }
    cout << max((cnt - 1) * 2 + 1, (n - cnt) * 2);
}

F 递推 矩阵加速

打表后可以发现存在递推式:\(f_{i} = f_{i - 1} * 3 - f_{i-2}\)。这么大的n直接\(o(n)\)肯定会寄,于是用矩阵加速的方法来写。

\[[f_{i - 1},f_{i - 2}] *\begin{bmatrix} 3 & 1\\ -1 & 0 \\ \end{bmatrix}=[f_{i}, f_{i - 1}] \]

// Author: yukito8069
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
typedef long long ll;
typedef double dd;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
struct matrix {
    ll a[3][3];
}a;
matrix matrix_mul(matrix a, matrix b) {
    matrix ret;
    memset(ret.a, 0, sizeof(ret.a));
    for (int i = 1; i <= 2; i++) {
        for (int j = 1; j <= 2; j++) {
            ll cur = 0;
            for (int k = 1; k <= 2; k++) {
                cur = (cur + (a.a[i][k] % mod) * (b.a[k][j] % mod) % mod + mod) % mod;
            }
            ret.a[i][j] = cur % mod;
        }
    }
    return ret;
}
matrix matrix_qmi(matrix a, ll z) {
    matrix ret; memset(ret.a, 0, sizeof(ret.a));
    ret.a[1][1] = ret.a[2][2] = 1ll;
    matrix tmp = a;
    while(z) {
        if(z & 1ll) {
            ret = matrix_mul(ret, tmp);
        }
        z >>= 1ll;
        tmp = matrix_mul(tmp, tmp);
    }
    return ret;
}
int main() {
	int T;
	cin >> T;
	while (T--) {
        matrix cc;
        memset(cc.a, 0, sizeof(cc.a));
        cc.a[1][1] = 2ll;
        cc.a[1][2] = 1ll;
        memset(a.a, 0, sizeof(a.a));
        a.a[1][1] = 3ll, a.a[1][2] = 1ll; a.a[2][1] = -1ll;
        ll n; cin >> n;
        if(n == 1) {
            cout << 1 << "\n";
            continue;
        }
        if(n == 2) {
            cout << 2 <<"\n";
            continue;
        }
        matrix ans = matrix_qmi(a, n - 2ll);
        matrix ans2 = matrix_mul(cc, ans);
        cout << ans2.a[1][1] << "\n";
    }
	return 0;
}

posted @ 2022-05-12 12:56  行行子  阅读(290)  评论(0)    收藏  举报