Educational Codeforces Round 131 (Rated for Div. 2) ABCD
Educational Codeforces Round 131 (Rated for Div. 2)
https://codeforces.com/contest/1701
A. Grass Field
统计1的个数cnt:
- cnt=0,则ans=0
- 0<cnt<4,则ans=1
- cnt=4,则ans=2
(直接加起来也行,这里写的不是很优雅)
#include <bits/stdc++.h>
using namespace std;
void solve () {
int x, cnt = 0;
for (int i = 0; i < 4; i ++) {
cin >> x;
if (x == 1) cnt ++;
}
if (cnt == 0) cout << "0\n";
else if (cnt < 4) cout << "1\n";
else cout << "2\n";
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
B. Permutation
d=2时,一定最优。因为长度固定的情况下,2的指数次增长比其他数字都慢。考虑如何构造:
一开始想的是按照质数的倍数来筛,但是诸如30(235)就没法构造进去。。
所以还是直接暴力构造吧(允悲)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
int a[N+5];
// bool is_prime (int x) {
// if (x == 1) return true;
// if (x == 2) return false;
// for (int i = 2; i*i <= x; i ++)
// if (x%i == 0) return false;
// return true;
// }
// void pre () {
// int k = 1;
// for (int i = 1; i <= N; i ++)
// if (is_prime (i)) a[k++] = i;
// }
void solve () {
int n; cin >> n;
cout << "2\n";
//int res = n;
bitset<N>vis;
for (int i = 1; i <= n; i ++) {
if (vis[i]) continue;
for (int j = i; j <= n; j *= 2)
vis[j] = true, cout << j << ' ';
}
cout << endl;
}
int main () {
//pre();
int t;
cin >> t;
while (t --) solve ();
}
//d=2时最优
//先预处理
C. Schedule Management
二分答案(考虑性质:最大时间最小)(工作是同时进行的)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5;
int a[N];
int n, m;
bool check (int x) {
int time = 0, need = 0;
for (int i = 1; i <= n; i ++) {
if (a[i] >= x) need += a[i] - x; //人手足够
else time += (x - a[i]) / 2; //要派x-a[i]个人来额外协助,这部分人用过了,所以除2
}
return time >= need;
}
void solve () {
memset (a, 0, sizeof a);
cin >> n >> m; //工人数,任务数
set<int> s;
for (int i = 1; i <= m; i ++) {
int x; cin >> x;
a[x] ++; //该工人可以胜任多少份工作
s.insert (x);
}
//每个工作都由不同的人负责
if (s.size () == m) {
cout << "1\n";
return ;
}
int l = 1, r = 2 * m + 1;
while (l < r) {
int mid = l + r >> 1;
if (check (mid)) r = mid;
else l = mid + 1;
}
cout << l << endl;
}
signed main () {
int t;
cin >> t;
while (t --) solve ();
}
//二分答案
//dp
//f[i][j]:当前进行到第i个任务,选择编号为j的工人
//维护一个vis[N],表示当前工人是否可用
//贪心
//排序,统计每个连续段个数
//把每个所需时间放进来
D. Permutation Restoration
已知\(b_i=\frac{i}{a_i}\) (下取整),给定\(b_i\),要还原数列a[]
解:
\[\rightarrow b[i]\leq \frac{i}{a[i]}<b[i]+1\rightarrow \frac{i}{b[i]+1}< a[i]\leq \frac{i}{b[i]}
\]
\((b[i]=0时, \frac{i}{b[i]}=n)\)
然后枚举i为要放置的数
根据贪心的策略,每次都选择最小的右端点R(能放下更多的数)
故把满足\(L\leq i\)的区间\([L,R]\)放入堆中,然后每次取出最小的\(R\)即可
(代码参考ygg)
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 5e5 + 5;
int a[N], b[N];
void solve () {
int n; cin >> n;
vector <pii> v[n+1];
for (int i = 1; i <= n; i ++) {
cin >> b[i];
int L = i / (b[i] + 1) + 1; //要再+1,因为左端点取不到等号
int R = b[i] == 0 ? n : i/b[i];
v[L].push_back ({R, i}); //方便按照数轴顺序来提取区间
}
priority_queue <pii, vector <pii>, greater<pii>> q; //存最近R的区间堆
for (int i = 1; i <= n; i ++) {
for (auto j : v[i]) q.push (j);
auto t = q.top();
q.pop();
a[t.second] = i;
}
for (int i = 1; i <= n; i ++) cout << a[i] << ' ';
cout << endl;
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}