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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章