2024“圖森未來杯”程式設計邀請賽

PHarr發表於2024-05-04

https://voj.mobi/contest/242/problems,密碼2024ecnutsol

A - 調和與折中

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;


using vi = vector<int>;


i32 main(){
	ios::sync_with_stdio(false), cin.tie(nullptr);
	i64 a, b, c, d, e, f;
	cin >> a >> b >> c >> d >> e >> f;
	if(f * (a * c + b) == c * (d * f + e)) cout << "Yes\n";
	else cout << "No\n";
	return 0;
}

B - 數位遊戲

如果\(x<10\) 且為奇數,則無解。

否則記\(cnt=bitcnt(p)\),如果\(cnt\)為偶數,則一定存在一種不進位的方法,則答案為\(cnt/2\),否則存在一種只進一次位的方法,則答案為\(cnt/2+5\)

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;


using vi = vector<int>;

void solve(){
	string s;
	cin >> s;
	if(s.size() < 2 and (s.front() - '0') % 2 == 1) {
		cout << "-1\n";
		return;
	}
	int cnt = 0;
	for(auto i : s) cnt += i - '0';
	if(cnt % 2 == 0) cout << cnt / 2 << "\n";
	else cout << cnt / 2 + 5 << "\n";
	return;
}

i32 main(){
	ios::sync_with_stdio(false), cin.tie(nullptr);
	int TC;
	for(cin >> TC; TC; TC --)
		solve();
	return 0;
}

C - 抽卡與破防

根據題目可以得到出六星的機率

\[p(x) = \left\{\begin{matrix} \frac {a}{100} & x \le n\\ \min(\frac{a + (x-n)b}{100},100)& x > n \end{matrix}\right. \]

然後可以得到不出六星的機率\(arcp(x) = 1 - p(x)\)

對於出六星是 up 的機率是\(q = \frac{c}{100}\),歪的機率是\(arcq = 1 - q\)

\(E(i,j)\)表示從第\(i\)抽抽卡開始,累計\(j\)抽未出六星是,抽出\(up\)的機率是多少

對於沒有到達保底的的情況\(i<m\)

\[E(i,j) = 1 + p(j) \times(arcq \times E(i+1,0) + q\times 0) + arcp[j] \times E(i+1,j+1) \]

對於已經到達保底的情況\(i>m\)

\[E(i,j) = 1 + p(j) \times 0 + arcq(j)\times E(i + 1 , j + 1) \]

然後我們遞迴加記憶化就可以的了,遞迴的過程中,如果已經到達保底出六星也就是\(arcq[j] = 0\)時就不要在搜尋\(E(i+1,j+1)\)

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;


#define int i64

using vi = vector<int>;

const int N = 200, M = 20000, mod = 1e9+7;

int e[M + 1][N + 1], p[N + 1], arcp[N + 1];
int n, m, a, b, c, q, arcq;

int power(int x, int y) {
	int ans = 1;
	while(y) {
		if(y & 1) ans = ans * x % mod;
		x = x * x % mod;
		y >>=1;
	}
	return ans;
}

int inv(int x) {
	return power(x, mod - 2);
}


void init(){
	int inv100 = inv(100);

	q = c * inv100 % mod;
	arcq = (100 - c) * inv100 % mod;

	for(int x = 0; x <= N; x ++){
		if(x <= n) p[x] = a * inv100 % mod;
		else p[x] = min(a + (x - n) * b, 100ll) * inv100 % mod;
		arcp[x] = (1ll - p[x] + mod) % mod;
	}	
	for(int i = 0; i <= M; i ++)
		for(int j = 0; j <= N; j ++) 
			e[i][j] = -1;
	return;
}

int E(int i ,int j) {
	if(e[i][j] != -1) return e[i][j];
	if(i < m) {
		e[i][j] = 1;
		if(arcp[j] % mod != 0) e[i][j] = (e[i][j] + arcp[j] * E(i + 1, j + 1) % mod) % mod; // 沒出六星
		e[i][j] = (e[i][j] + p[j] * arcq % mod * E(i + 1 , 0) % mod ) % mod; // 出六星 但不是 up
	
	} else { // 出六星必 up
		e[i][j] = 1;
		if(arcp[j] % mod != 0) e[i][j] = (e[i][j] + arcp[j] * E(i + 1, j + 1)) % mod; // 沒出六星
	}
	assert(e[i][j] >= 0);
	return e[i][j] %= mod;
}


i32 main(){
	ios::sync_with_stdio(false), cin.tie(nullptr);
	cin >> n >> m >> a >> b >> c;
	init();
	cout << E(0, 0);
	return 0;
}

F - 花獅平衡樹

想了很久,最後還是用裸的 splay樹實現的。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using i64 = long long;
using ll = long long;

using vi = vector<int>;
using pii = pair<int, int>;



const int N = 5e5+5;

int n;

struct Splay {
    int rt, tot, fa[N], ch[N][2], val[N], cnt[N], siz[N];
    int tag[N];
    void push_up(int x) {
        siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x];
    }
    void push_down(int x) {
        if (x && tag[x]) {
            if (ch[x][0])tag[ch[x][0]] ^= 1;
            if (ch[x][1])tag[ch[x][1]] ^= 1;
            swap(ch[x][0], ch[x][1]);
            tag[x] = 0;
        }
    }
    bool get(int x) { return x == ch[fa[x]][1]; }
    void clear(int x) {
        ch[x][0] = ch[x][1] = fa[x] = val[x] = siz[x] = cnt[x] = 0;
    }

    void rotate(int x) {
        int y = fa[x], z = fa[y], chk = get(x);
        push_down(x);
        push_down(y);
        ch[y][chk] = ch[x][chk ^ 1];
        if (ch[x][chk ^ 1]) fa[ch[x][chk ^ 1]] = y;
        ch[x][chk ^ 1] = y;
        fa[y] = x;
        fa[x] = z;
        if (z) ch[z][y == ch[z][1]] = x;
        push_up(y);
    }
    void splay(int x, int goal) {
        for (int f = fa[x]; (f = fa[x]) != goal; rotate(x))
            if (fa[f] != goal) rotate(get(x) == get(f) ? f : x);
        if (goal == 0)rt = x;
    }
    void splay(int x) {
        splay(x, 0);
    }
    int kth(int k) {

        int cur = rt;
        while (1) {
            push_down(cur);
            if (ch[cur][0] && k <= siz[ch[cur][0]]) {
                cur = ch[cur][0];
            }
            else {
                k -= cnt[cur] + siz[ch[cur][0]];
                if (k <= 0) {
                    splay(cur);
                    return cur;
                }
                cur = ch[cur][1];
            }
        }
    }
    int find(int x) {
        return kth(x + 1);
    }
    int build(int L, int R, int father) {
        if (L > R) { return 0; }
        int x = ++tot;
        int mid = (L + R) / 2;
        fa[x] = father;
        cnt[x] = 1;
        val[x] = mid;
        ch[x][0] = build(L, mid - 1, x);
        ch[x][1] = build(mid + 1, R, x);
        push_up(x);
        return x;
    }
    void rev(int L, int R) {
        int fl = find(L - 1);
        int fr = find(R + 1);
        splay(fl, 0);
        splay(fr, fl);
        int pos = ch[rt][1]; pos = ch[pos][0];
        tag[pos] ^= 1;
    }
    void dfs(int x) {
        push_down(x);
        if (ch[x][0])dfs(ch[x][0]);
        if (val[x] != 0 && val[x] != (n + 1))cout << val[x] << " ";
        if (ch[x][1])dfs(ch[x][1]);
    }
} tree;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int m;
    cin >> n >> m;
    tree.build(0, n + 1 , 0);
	tree.rt = 1;
	while(m -- ){
		int l , r;
		cin >> l >> r;
		tree.rev(l ,r);
	}
	tree.dfs(tree.rt);
    return 0;
}

H - 橡木蛋糕卷

首先我們計算出每個傳送點到所有的蛋糕店的最短距離,然後就轉換成了經典旅行商問題,用狀壓 dp 來解決。

#include <bits/stdc++.h>

using namespace std;


using i32 = int32_t;
using ll = long long;


using vi = vector<int>;
using pii = pair<int, int>;

const int N = (1 << 18) + 8;

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

int stos[20][20];

int dp[N][20];

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);

    int n,m;cin >> n >> m;

    vector<vector<char>> a(n + 1,vector<char>(m + 1));
    vector<pair<int,int>> t(1),s(1);

    for (int i = 1;i <= n;i++){
        for (int j = 1;j <= m;j++){
            cin >> a[i][j];
            if (a[i][j] == 'S') s.push_back({i,j});
            if (a[i][j] == 'T') t.push_back({i,j});
        }
    }

    auto bfs = [&](int sx,int sy)->vector<vector<int>>{
        queue<pair<int,int>> q;
        q.push({sx,sy});
        vector<vector<int>> vis(n + 1,vector<int>(m + 1));
        vector<vector<int>> d(n + 1,vector<int>(m + 1, 1e9));
        d[sx][sy] = 0;
        vis[sx][sy] = 1;
        while (!q.empty()){
            auto [x,y] = q.front();
            q.pop();
            for (int i = 0;i < 4;i++){
                int u = x + dx[i],v = y + dy[i];
                if (u < 1 || v < 1 || u > n || v > m || vis[u][v] || a[u][v] == '#'){
                    continue;
                }
                q.push({u,v});
                d[u][v] = d[x][y] + 1;
                vis[u][v] = 1;
            }
        }
        return d;
    };
    int siz = s.size() - 1;
    vector<int> ttos(s.size(),1e9);
    int idx = 0;

    for( int i = 0 ; i < 20 ; i ++ )
        for( int j = 0 ; j < 20 ; j ++ )
            stos[i][j] = 1e9;

    for (int i = 1;i < s.size();i++){
        auto [x,y] = s[i];
        auto tmp = bfs(x,y);
        for (int j = 1;j < s.size();j++){
            auto [u,v] = s[j];
            stos[i][j] = min(stos[i][j],tmp[u][v]);
        }
        for (auto [u,v] : t){
            ttos[i] = min(ttos[i],tmp[u][v]);
        }
    }

    for (int i = 1;i < (1 << siz);i++){
        for (int j = 0;j < 20;j++){
            dp[i][j] = 1e9;
        }
    }

    dp[0][0] = 0;

    for (int i = 1;i < (1 << siz);i++){
        for (int j = 1;j <= siz;j++){
            if ((i >> (j - 1)) & 1){ // END
                int tmp = 1e9;
                for (int k = 1;k <= siz;k++){ // ST
                    if ((i >> (k - 1) )& 1 && k != j){
                        tmp = min(tmp,dp[i - (1 << (j - 1))][k]);
                        dp[i][j] = min(dp[i][j],dp[i - (1 << (j - 1))][k] + stos[j][k]);
                    }
                }
                if (tmp == 1e9) tmp = 0;
                dp[i][j] = min(dp[i][j],tmp + ttos[j]);
            }
        }
    }

    int ans = 1e9;

    for (int i = 1;i <= siz;i++){
        ans = min(dp[(1 << siz) - 1][i],ans) ;
    }

    cout << ans << endl;

    return 0;
}

相關文章