1. 程式人生 > 其它 >2021杭州師範大學acm新生賽題解

2021杭州師範大學acm新生賽題解

看情況更新

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);
}