题解 CF1574D The Strongest Build

\(2000\) 分的题我赛场上居然没有做出 qwq
想得太复杂了。

\(n\) 列数每列取一个,\(m\) 种取法不行,求和最大的取法。

受到以前贪心讲课的一道题的影响,看到我就想着把前 \((m+1)\) 大的方案都求出来,存进 \((m+1)\)twt 里面,然后排个序看看哪个没出现就是了。

如何求前 m+1 大?

考虑两个的合并,若 \((i, j)\) 是当前最大的,那么下一个大的可能是 \((i+1, j)\)\((i, j+1)\),这两个塞进优先队列里就好了,把这个过程重复 \((m-1)\) 次就可以得到前 \(m\) 大的。

代码
#include <iostream>
#include <set>
#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>
#include <map>
#define int long long
const int base = 2333, P = 10'0000'0103;
int n, k, m;
std::vector<int> a[15];
struct dwd {
    int a, x, y;
    dwd(int _a, int _x, int _y) { a = _a, x = _x, y = _y; }
    bool operator < (dwd b) const { 
        if (a != b.a) return a > b.a ; 
        if (x != b.x) return x < b.x;
        if (y != b.y) return y < b.y;
        return false;
    }
};
struct twt {
    std::vector<int> b;
    int val, hash;
    void push(int x) { 
        int now = b.size(); 
        b.push_back(x), val += a[now+1][x]; 
        hash = (hash * base % P + a[now+1][x]) % P;
    }
    twt(int x) { hash = 0, val = 0; b.clear();  push(x); }
    twt() { hash = 0, b.clear(); val = 0; }
    bool operator < (const twt &z) const { 
        if (val != z.val) return val > z.val;  
        else return hash < z.hash;
    }
    bool operator != (const twt &z) {
        for (int i = 0; i < n; i++) if (b[i] != z.b[i]) return true;
        return false;
    }
    friend std::ostream& operator << (std::ostream& out, twt x) { 
        for (int i = 0; i < (int)x.b.size(); i++) 
            out << a[i+1][0]-x.b[i]+1 << ' '; 
        return out;
    }
};
std::vector<twt> s, tmp, fo;
std::set<dwd> t;
std::map<twt, bool> map;
void merge(int q) {
    t.clear(), tmp.clear();
    t.insert(dwd(s[0].val + a[q][1], 0, 1));
    while (tmp.size() <= m+1  && !t.empty()) {
        int i = t.begin()->x, j = t.begin()->y;
        t.erase(t.begin());
        twt cur = s[i];
        cur.push(j);
        tmp.push_back(cur);
        if (i+1 < (int)s.size()) t.insert(dwd(s[i+1].val + a[q][j], i+1, j));
        if (j+1 <= a[q][0]) t.insert(dwd(s[i].val + a[q][j+1], i, j+1));
        // cnt ++;
    }
    s = tmp;
    std::sort(s.begin(), s.end());
}
signed main() {
    std::cin >> n;
    for (int i = 1; i <= n; i++) {
        std::cin >> k;
        a[i].resize(k+1), a[i][0] = k;
        for (int j = 1; j <= k; j++) std::cin >> a[i][j];
        std::sort(std::next(a[i].begin()), a[i].end(), std::greater<int>());
    } 
    std::cin >> m;
    for (int i = 1; i <= a[1][0]; i++) s.push_back(twt(i));
    std::sort(s.begin(), s.end());
    for (int i = 2; i <= n; i++) merge(i);
    for (int i = 1; i <= m; i++) {
        twt cur;
        for (int j = 1; j <= n; j++) std::cin >> k, cur.push(a[j][0]-k+1);
        map[cur] = 1;
    }
    int j = 0;
    for (auto cur : s) if (!map[cur]) return std::cout << cur, 0;
}

赛时因为 比较没有严格弱序 + 奇怪的错误 没能通过。
其实还是因为思维不够,马量来凑。

稍微观察就可以发现答案要么是每组取最大,要么是某个被禁掉的某一位少一个,那么枚举就好了。

就 是 这 么 简 单

#include <iostream>
#include <vector>
#include <map>
#define int long long
int n, m, mx;
std::vector<int> a[15], ab[100005], v, ans;
std::map<std::vector<int>, bool> map;
std::ostream& operator << (std::ostream& out, std::vector<int> a) {
	for (int i = 0; i < (int)a.size(); i++) out << a[i] << ' ';
	return out;
}
signed main() {
	std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
	std::cin >> n;
	for (int i = 1, k; i <= n; i++) {
		std::cin >> k;
		a[i].resize(k+1), a[i][0] = k, v.push_back(a[i][0]);
		for (int j = 1; j <= a[i][0]; j++) std::cin >> a[i][j];
	}
	ans = v;
	std::cin >> m;
	for (int i = 1, k; i <= m; i++) {
		v.clear();
		for (int j = 1; j <= n; j++) std::cin >> k, v.push_back(k);
		map[v] = 1, ab[i] = v;
	}
	if (!map.count(ans)) return std::cout << ans, 0;
	for (int i = 1; i <= m; i++) {
		for (int j = 0; j < n; j++) {
			if (ab[i][j] <= 1) continue;
			ab[i][j] --;
			int an = 0;
			for (int k = 1; k <= n; k++) an += a[k][ab[i][k-1]];
			if (!map.count(ab[i]) && an > mx) mx = an, ans = ab[i];
			ab[i][j] ++;
		}
	}
	std::cout << ans;
}

所以比赛时别着急写,这种“老题翻新”系列自有其自己的做法,怎么可能让你把原来的做法改一改就过呢?

posted @ 2021-09-22 18:59  Acfboy  阅读(82)  评论(0编辑  收藏  举报