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:

  1. cnt=0,则ans=0
  2. 0<cnt<4,则ans=1
  3. 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 ();
}

E. Text Editor

F. Points

posted @ 2022-07-09 11:33  Sakana~  阅读(48)  评论(0编辑  收藏  举报