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} $
C. Decreasing String
数据结构:单调栈
维护一个递增的单调栈即可,因为利用其可以快速的找到每一次删去哪个字符最划算
如果说从前往后第一次遇到 $c[i] > c[i + 1] $,那么这一轮一定移除字符 $c[i] $,否则就移除最后一个字符,这样操作才能每回都得到字典序最小的串
那么利用预处理 + 二分得知需要移除几个字符,单调栈依次移除后判断答案字符的最终位置即可
D. Monocarp and the Set
其实 D 题是个诈骗题?
首先考虑一个问题,给定的字符串的第一个字符一定不能是 '?',如果是的话,那么就无解了,因为插入的第二个字符一定是最大的或者最小的,起码要第三个字符才能出 '?'
如果说给定的字符串的第 i 个字符是 '?',那么答案的可能方案数 $\times (i - 1) $,因为前 i 个字符已经确定了,现在再插入一个中间的字符,共有 i - 1 种可能。
如果说后面的操作将第 j 个字符由 '?' 改为 '<' 或 '>',那么答案 / (i - 1)
如果说后面的操作将第 j 个字符由 '<' 或 '>' 改为 '?',那么答案 * (i - 1)
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;
}