0%

Codeforces - Educational Codeforces Round 145

Contestant. Rank 2205. Rating -13.

A. Garland

题意

给定 盏灯的颜色,颜色为 内的任意数字。初始状态所有灯均关闭,打开一盏灯的条件是之前打开的灯的颜色与其不一致,第一次可以打开任意一盏灯。输出将所有灯打开所需最小次数。

思路

首先,这题只有 盏灯。

所以,我们直接分类讨论即可。

我们先将灯按照颜色代码升序排序,那么如果第一个数和最后一个数相等,输出

否则,前三个数相等或者后三个数相等时,需要 次;

否则, 次足矣。

时间复杂度:

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

void init(){}

void solve() {
    string s;
    cin >> s;
    sort(s.begin(), s.end());
    if(s[0] == s[3]) cout << -1 << '\n';
    else if(s[0] == s[2] || s[1] == s[3]) cout << 6 << '\n';
    else cout << 4 << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

我居然没看到只有4个…

B. Points on Plane

题意

给定整数 ,代表当前有 个点。将这些点放入平面直角坐标系,满足坐标均为整数。在限制任意一对点的距离都严格大于 的条件下,输出最小的总代价。其中,对于一个点 ,单点的代价为 ,总代价为所有点的代价最大值。

思路

我们来固定

  1. ,那么

  2. ,那么

归纳可得,对于 的所有正数取值, 的取值总数为

同理, 为负数时, 的取值总数为

那么,我们可以得到总和

那么,最后的答案即为

注意精度问题即可。

时间复杂度:

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

void init(){}

void solve() {
    int n;
    cin >> n;
    int ans = sqrt(n);
    if(ans * ans < n) ans ++;
    cout << ans - 1 << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

离谱的是在 C++ 17 下, 可以作为答案卡过去

C. Sum on Subarrays

题意

构造一个序列,满足所有连续子序列的和均不为 ,且和为正数的序列数量为给定值

思路

首先,我们不妨打表, 个数的连续子序列个数,即

那么,我们不难发现,

那么,在 个数的基础上,我们再添加 个数,就可以等于

更具体地说,我们不妨在序列前面放上 个相同的正数 ,其中 中第一个不大于 的值。

那么,我们还需 个数,我们不妨在后面放一个负数 ,让 以这个数作为结尾的 子序列的和 为负数 的个数为

这样的话,以 为头,负数 为尾的子序列的和就是正数了。

剩下还有一些空位,我们填上负无穷大,也就是最小值 即可。

当然,正数 不能为 ,这样会让某个总和变为 ,那么我们取 即可。

在取 的条件下,负数

当然,我们用递增的序列取代这些相等的正数也是可以的。

时间复杂度:

对应AC代码1

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

vector<int> s = {0};

void init(){
    for(int i=1;i<=1000;i++)
        s.emplace_back(i *  (i + 1) / 2);
}

void solve() {
    int n, k;
    cin >> n >> k;
    int q = upper_bound(s.begin(), s.end(), k) - s.begin() - 1;
    int cnt = k - s[q];
    for(int i=0;i<q;i++) cout << 2 << ' ';
    if(cnt != 0) cout << -(q - cnt) * 2 - 1 << ' ', q ++;
    for(int i=q;i<n;i++) cout << -1000 << ' ';
    cout << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

对应AC代码2

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

vector<int> s = {0};

void init(){
    for(int i=1;i<=1000;i++)
        s.emplace_back(i *  (i + 1) / 2);
}

void solve() {
    int n, k;
    cin >> n >> k;
    int q = 0;
    while(s[q + 1] <= k) q ++;
    for(int i=0;i<q;i++) cout << q - i + 1 << ' ';
    k -= s[q];
    if(k != 0) {
        cout << -1 * (s[q - k] + q - k + 1) << ' ';
        q ++;
    }
    for(int i=q;i<n;i++) cout << -1000 << ' ';
    cout << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

我怎么就这么蠢.jpg

D. Binary String Sorting

题意

给定一个二进制字符串,规定操作为下面两个任选一:

  1. 交换两个相邻元素;

  2. 删掉一个元素

第一个操作的代价为 ;第二个操作的代价为

输出让整个字符串变为不递减序列的最小代价。

思路

首先,这题可以 ,但是我们不妨来想想怎么贪心。

我们下面有四种方案,取最小值即可:

  1. 删掉所有的

  2. 删掉所有的

  3. 遍历所有的 ,将前面的 删掉,后面的 删掉;

  4. 遍历所有的 ,若前面为 ,那么把这个 和当前的 交换,然后删去前面剩余的 ,以及后面的

前面三者是显然的,而对于第四个,我们不妨考虑其他的移动情况。

显然, 没必要交换; 不用管,因为满足递增; 交换即可;剩余的情况,我们都需要移动至少两次,那还不如删掉呢。

因此,贪心是成立的。

时间复杂度:

对应AC代码

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define pii pair<int, int>
#define fs first
#define sc second

const int N = 2e5 + 10, inf = 0x3f3f3f3f3f3f3f3f;

void init(){}

void solve() {
    int x = 1e12;
    string s;
    cin >> s;
    int n = s.size();
    s = " " + s;
    vector<vector<int>> pre(n + 1, vector<int>(2, 0));
    int cnt0  = 0;
    for(int i=1;i<=n;i++){
        int now = s[i] - '0';
        if(now == 0) cnt0 ++;
        pre[i][now] = pre[i - 1][now] + 1;
        pre[i][1 - now] = pre[i - 1][1 - now];
    }
    int ans = min(cnt0, n - cnt0) * (x + 1);
    for(int i=1;i<=n;i++){
        if(s[i] == '0') {
            ans = min(ans, (pre[i][1] + cnt0 - pre[i][0]) * (x + 1));
            if(s[i - 1] == '1') ans = min(ans, x + (pre[i][1] + cnt0 - pre[i][0] - 1) * (x + 1));
        }
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    init();
    int t;
    cin >> t;
    while(t --) solve();
}

赛时一看到dp就溜了((