srm 549

歡迎點此閱讀QvQ

250


Description

有兩個集合,每個集合有N(N<50) 個錐面(表示爲高H 和底面半徑R ,均小於10000 )。要求從集合1 和集合2 的笛卡爾積集合中選取最多的元素滿足如下性質:
* (1): Ha / Ra > Hb / Rb
* (2): Ra < Rb

Solution

很顯然的一個二分圖匹配

Code

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define F first
#define S second
typedef long long LL;
typedef pair<int, int> pii;
const int N = 55;
int g[N][N], l[N], vis[N];
bool can(int u, int m) {
    for (int i = 0; i < m; ++i) {
        if (g[u][i] && !vis[i]) {
            vis[i] = 1;
            if (l[i] == -1 || can(l[i], m)) {
                l[i] = u;
                return 1;
            }
        }
    }
    return 0;
}
struct PointyWizardHats {
    int getNumHats(vector <int> th, vector <int> tr, vector <int> bh, vector <int> br) {
        int n = th.size(), m = bh.size();
        memset(l, -1, sizeof(l));
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < m; ++j) {
                if (th[i] * br[j] > tr[i] * bh[j] && tr[i] < br[j]) g[i][j] = 1;
            }
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            memset(vis, 0, sizeof(vis));
            if (can(i, m))  ++ans;
        }
        return ans;
    }
};

600


Description

AB 博弈。 在N×N(N13) 的矩陣上,有一些H 格子, 一開始每個H 格子裏最多有一枚帶權值的硬幣。 每次小B 選一個H 格子,然後小A 將硬幣任意排列後,將該格子的硬幣給小B
排列後必須滿足如下條件:
* (1): 每個格子必須有最多一枚硬幣,小B 選的格子可以沒有硬幣
* (2): 每一行,每一列,H 的個數和硬幣的個數之和必須是偶數

B 想獲得儘量多的權值,A 想讓對面獲得儘量少的權值

Solution

觀察到,如果B 能獲得k 個硬幣的話,一定獲得的是權值最小的k 的硬幣。
考慮到H 格子的情況,其實只有三種
* (1):沒選擇這個格子
* (2): 選擇了這個格子,下面沒有硬幣
* (3): 選擇了這個格子,下面有硬幣

容易想到三進制壓縮,考慮狀壓dp,用三進制狀態表示,用記憶化搜索比較容易實現。枚舉當前選擇的格子,枚舉兩種有無硬幣的情況即可。

Code

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define F first
#define S second
typedef long long LL;
typedef pair<int, int> pii;
vector<pii> g;
const int N = 13, inf = 100;
struct MagicalHats {
    int p[N], r[N], c[N], dp[1594323];
    int n, m, totcoin, tothat, num;
    inline int gao(int mask, int i, int s) {// 0:not selected 1:no coin 2:has coin
        return mask + s * p[i];
    }
    inline int get(int mask, int i) {
        return (mask / p[i]) % 3;
    }
    int dfs(int mask, int cocnt, int hatcnt, int r[], int c[]) {
        if (~dp[mask]) return dp[mask];
        int &t = dp[mask];
        t = -inf;
        if (hatcnt == tothat) {
            if (cocnt != totcoin)   return t = -inf;
            for (int i = 0; i < n; ++i) 
                if (r[i] & 1)   return t = -inf;
            for (int i = 0; i < m; ++i)
                if (c[i] & 1)   return t = -inf;
            return t = 0;
        }
        for (int i = 0; i < tothat; ++i) {
            int x = g[i].F, y = g[i].S;
            int s = get(mask, i);
            if (!s) {//not selected
                int t1 = -inf, t2 = -inf, state;
                if (cocnt < totcoin) {//has coin
                    int cnt = 1;
                    if (hatcnt >= num)  cnt = 0;
                    state = gao(mask, i, 2);
                    r[x] += 2;
                    c[y] += 2;
                    t1 = dfs(state, cocnt + 1, hatcnt + 1, r, c) + cnt;
                    r[x] -= 2;
                    c[y] -= 2;
                }
                //no coin
                ++r[x];
                ++c[y];
                state = gao(mask, i, 1);
                t2 = dfs(state, cocnt, hatcnt + 1, r, c);
                --r[x];
                --c[y];
                if (t1 < 0) t = max(t, t2);
                if (t2 < 0) t = max(t, t1);
                t = max(t, min(t1, t2));
            }
        }
        return t;
    }
    int findMaximumReward(vector <string> board, vector <int> coins, int numGuesses) {
        p[0] = 1;
        for (int i = 1; i < 13; ++i)    p[i] = p[i - 1] * 3;
        this -> n = board.size(), this -> m = board[0].size();
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < m; ++j)
                if (board[i][j] == 'H') g.pb(mp(i, j));
        this -> totcoin = coins.size(), this -> tothat = g.size(), this -> num = numGuesses;
        memset(dp, -1, sizeof(dp));
        int cnt = dfs(0, 0, 0, r, c);
        sort(coins.begin(), coins.end());
        if (cnt < 0)    return -1;
        int ans = 0;
        for (int i = 0; i < cnt; ++i)   ans += coins[i];
        return ans;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章