Educational Codeforces Round 156 (Rated for Div. 2) - A B C(单调栈) D(思维) E(状压DP)

Educational Codeforces Round 156 (Rated for Div. 2)
E 题待理解

A. Sum of Three

如果说给定的数为 n

  • 如果 \(n \le 6\)\(n = 9\) 时,无法分解
  • 反之,如果 $n \% 3 \ne 0 $ 时,可以分解为 1, 2, n - 3
  • 反之,如果 $n \% 3 = 0 $ 时,可以分解为1, 4, n - 5

B. Fear of the Dark

计算 \(d_{OA}\)\(d_{OB}\)\(d_{PA}\)\(d_{PA}\)\(d_{AB}\)
如果 O 点和 P 点均离点 X(X 为 A 或 B) 近,那么答案即为 $max(d_{OX}, d_{PX}) $
反之,如果说两圆相切半径能包住两点,则答案即为 \(d_{AB} / 2\)
反之,答案即为 $max(d_{OX}, d_{PY}) ,d_{OX} = min(), d_{PY} $

Qiansui_code

C. Decreasing String

数据结构:单调栈
维护一个递增的单调栈即可,因为利用其可以快速的找到每一次删去哪个字符最划算
如果说从前往后第一次遇到 $c[i] > c[i + 1] $,那么这一轮一定移除字符 $c[i] $,否则就移除最后一个字符,这样操作才能每回都得到字典序最小的串

那么利用预处理 + 二分得知需要移除几个字符,单调栈依次移除后判断答案字符的最终位置即可

Qiansui_code

D. Monocarp and the Set

其实 D 题是个诈骗题?
首先考虑一个问题,给定的字符串的第一个字符一定不能是 '?',如果是的话,那么就无解了,因为插入的第二个字符一定是最大的或者最小的,起码要第三个字符才能出 '?'
如果说给定的字符串的第 i 个字符是 '?',那么答案的可能方案数 $\times (i - 1) $,因为前 i 个字符已经确定了,现在再插入一个中间的字符,共有 i - 1 种可能。

如果说后面的操作将第 j 个字符由 '?' 改为 '<' 或 '>',那么答案 / (i - 1)
如果说后面的操作将第 j 个字符由 '<' 或 '>' 改为 '?',那么答案 * (i - 1)

Qiansui_code

E. I Wanna be the Team Leader

参考题解

对于某一个任务,所需的最少人数只与安排给当前任务的最小的抗压能力的人有关。我们将抗压能力按照从小到大排序,那么安排给某一任务的员工一定是一段连续区间的员工

而总任务数 $m \le 20 $,所以可以利用状压 DP 求解该问题
我们设 dp[i] 表示完成 i 所表示的任务共需要的员工数。如果说在其基础上我们再完成一项难度为 \(b_j\) 的任务,那么需要的人数是:
我们设 $t = dp[i] $
如果我们选取第 t + 1 个人作为最小抗压的人,那么至少需要 $\lceil b_j / a_{t + 1} \rceil $
如果我们选取第 t + 2 个人作为最小抗压的人,那么至少需要 \(\lceil b_j / a_{t + 2} \rceil + 1\)
如果我们选取第 t + 3 个人作为最小抗压的人,那么至少需要 \(\lceil b_j / a_{t + 2} \rceil + 2\)
$\dots $
我们想要使用尽可能少的人来完成这个任务,相当于我们需要在后面所有的人中选择一个作为最小抗压的人,这个选择显然可以通过 ST 表来进行预处理

为了最终输出答案,我们还需要在转移的过程中记录转移的过程,以便输出答案

详见代码

//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long

using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*

*/
const int N = 2e5 + 5, M = 22, inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f, mod = 998244353;

int logn[N];
void pre(){
	logn[1] = 0; logn[2] = 1;
	for(int i = 3; i < N; ++ i) logn[i] = logn[i / 2] + 1;
	return ;
}

template <typename T>
struct ST{
public:
	ST(T a[], int n){
		int t = logn[n] + 1;
		minv.resize(t);
		for(int i = 0; i < t; ++ i) minv[i].resize(n + 1);

		for(int i = 1; i <= n; ++ i) minv[0][i] = a[i];
		for(int j = 1; j < t; ++ j){
			for(int i = 1; i + (1 << j) - 1 <= n; ++ i){
				minv[j][i] = min(minv[j - 1][i], minv[j - 1][i + (1 << (j - 1))]);
			}
		}
	}
	T getmin(int l, int r){
		int k = logn[r - l + 1];
		return min(minv[k][l], minv[k][r - (1 << k) + 1]);
	}
private:
	vector<vector<T>> minv;
};

void solve(){
	int n, m;
	cin >> n >> m;
	pii a[n];
	int b[m];
	for(int i = 0; i < n; ++ i) cin >> a[i].first, a[i].second = i + 1;
	for(int i = 0; i < m; ++ i) cin >> b[i];
	sort(a, a + n);
	
	vector<ST<int>> v;
	for(int i = 0; i < m; ++ i){
		int t[n + 1];
		for(int j = 0; j < n; ++ j){
			t[j + 1] = j + ceil(1.0 * b[i] / a[j].first);
		}
		v.push_back(ST(t, n));
	}

	vector<int> dp(1 << m, inf), last(1 << m);
	dp[0] = 0;
	for(int i = 0; i < 1 << m; ++ i){
		if(dp[i] >= n) continue;
		for(int j = 0; j < m; ++ j){
			if(i >> j & 1) continue;
			int num = v[j].getmin(dp[i] + 1, n);
			if(num < dp[i | 1 << j]){
				dp[i | 1 << j] = num;
				last[i | 1 << j] = j;
			}
		}
	}

	if(dp[(1 << m) - 1] <= n){
		cout << "YES\n";
		int state = (1 << m) - 1;
		vector ans(m, vector<int>());
		while(state){
			int now = dp[state] - 1;
			int cnt = 1;
			while(cnt * a[now].first < b[last[state]]){
				-- now; ++ cnt;
			}
			for(int i = now; i < now + cnt; ++ i) ans[last[state]].push_back(a[i].second);
			state ^= 1 << last[state];
		}
		for(int i = 0; i < m; ++ i){
			cout << ans[i].size() << ' ';
			for(auto x : ans[i]) cout << x << ' ';
			cout << '\n';
		}
	}else cout << "NO\n";
	return ;
}

signed main(){
	pre();
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	int _ = 1;
	// cin >> _;
	while(_ --){
		solve();
	}
	return 0;
}
posted on 2023-10-10 20:53  Qiansui  阅读(32)  评论(0编辑  收藏  举报