Codeforces #640 div4 A - G 解题报告

A. Sum of Round Numbers

\(Description:\)

  给你一个数 \(n\),将其拆分为几个数的和,这几个数满足除最高位外,其余位全为 \(0\)

\(Solve:\)

  我直接以字符串读入,然后扫描一遍记下答案即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;

int main(){
    int t; cin >> t;
    while(t --){
        char num[10];
        scanf("%s", num + 1);
        vector<string> ans;
        int len = strlen(num + 1);
        for(int i = 1; i <= len; i ++){
            if(num[i] == '0') continue; // 是 0 就跳过
            string tmp = "";
            tmp += num[i];
            for(int j = 1; j <= len - i; j ++) tmp += '0'; // 加 0
            ans.push_back(tmp);
        }
        cout << ans.size() << endl;
        for(int i = 0; i < ans.size(); i ++) cout << ans[i] << " ";
        puts("");
    }
    return 0;
}

\(\\\)

B. Same Parity Summands

\(Description:\)

  给你 \(n, k\) 两个数,问是否存在数组 \(a\) 满足 \(n = a_1 + a_2 + a_3 +...+a_k\)\(a\) 里的数要么都是奇数,要么都是偶数。

\(Solve:\)

  根据 \(n, k\) 的奇偶性来分类讨论即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 110;

int a[N];

int main(){
    int t; cin >> t;
    while(t --){
        int n, k; cin >> n >> k;
        
        if(n & 1){ 
            if(k & 1){ 
                if(n < k) { puts("NO"); continue; } // 即使全为 1 都大于 n
                for(int i = 1; i < k; i ++) a[i] = 1;
                a[k] = n - k + 1;
            }else{ // k 是偶数不合法
                puts("NO"); continue;
            }
        }else{
            if(k & 1){
                if(n / 2 < k) { puts("NO"); continue; } // 是偶数每一项至少为 2
                for(int i = 1; i < k; i ++) a[i] = 2;
                a[k] = n - (k - 1) * 2;
            }else{
                // 这种情况下,每个数为奇数更优
                if(n < k) { puts("NO"); continue; }
                for(int i = 1; i < k; i ++) a[i] = 1;
                a[k] = n - k + 1;
            }
        }
        puts("YES");
        for(int i = 1; i <= k; i ++) printf("%d ", a[i]);
        puts("");
    }
    return 0;
}

\(\\\)

C. K-th Not Divisible by n

\(Description:\)

  给出 \(n, k\),输出不能被 \(n\) 整除的第 \(k\) 个数。

\(Solve:\)

  对于每 \(n\) 个数,都有 \(n - 1\) 个数不能被 \(n\) 整除,那么根据这个我们可以轻易算出第 \(k\) 个数。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main(){
    int t; cin >> t;
    while(t --){
        ll n, k; cin >> n >> k;
        ll t = k / (n - 1);
        ll c = k - t * (n - 1);
        long long ans = t * n + (c > 0 ? c : -1); // c = 0 就必须 -1
        cout << ans << endl;
    }
    return 0;
}

\(\\\)

D. Alice, Bob and Candies

\(Description:\)

  两个人轮流吃数组中的元素,一个从左往右,一个从右往左,第一次只吃 \(a[i]\),每次吃掉的元素和要严格大于上一个人吃的,求吃了几次和每个人吃了多少?

\(Solve:\)

  直接按照题意模拟即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;

int arr[N];

int main(){
    int t; cin >> t;
    while(t --){
        int n; cin >> n;
        for(int i = 1; i <= n; i ++) scanf("%d", &arr[i]);
        int l = 1, r = n, a = 0, b = 0;
        int prev_a = 0, prev_b = 0; // 上次吃的总和
        int i; // 移动次数
        for(i = 1; ; i ++){
            if(i & 1){
                while(l <= r){
                    a += arr[l];
                    prev_a += arr[l ++];
                    if(prev_a > prev_b){
                        prev_b = 0;
                        break;
                    }
                }
            }else{
                while(l <= r){
                    b += arr[r];
                    prev_b += arr[r --];
                    if(prev_b > prev_a){
                        prev_a = 0;
                        break;
                    }
                }
            }
            if(l > r) break;
        }
        printf("%d %d %d\n", i, a, b);
    }
    return 0;
}

\(\\\)

E. Special Elements

\(Description:\)

  长度为 \(n\) 的数组 \(a\),存在多少 \(a_i = a_l + a_{l+1} + ... + a_r(1\leq l < r\leq n,a_i \leq n)\) ? 相同元素也要记入答案中。

\(Solve:\)

  预处理出前缀和数组,然后来枚举区间 \([l, r]\) ,记录答案即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e4;

int a[N], sum[N], m[N];

int main(){
    int t; cin >> t;
    while(t --){
        memset(m, 0, sizeof m); 
        int n; cin >> n;
        sum[0] = 0;
        for(int i = 1; i <= n; i ++){
            scanf("%d", &a[i]);
            m[a[i]] ++; // 记录每个数出现的次数
            sum[i] = sum[i - 1] + a[i]; // 前缀和
        }
        int ans = 0;
        for(int l = 1; l <= n; l ++)
            for(int r = l + 1; r <= n; r ++){
                int t = sum[r] - sum[l - 1];
                if(t > n) continue; // 每个数都是 <= n,> n 显然不合法
                ans += m[t];
                m[t] = 0; // 加了必须清空
            }
        cout << ans << endl;
    }
    return 0;
}

\(\\\)

F. Binary String Reconstruction

\(Description:\)

  对于一个二进制字符串 \(s\),给出 \(n_0, n_1, n_2\),分别代表在 \(n - 1\) 对相邻字符组里面全是 \(0\),有 \(1\)\(0\),全是 \(1\) 的个数。输出满足一个这样条件的 \(s\)

\(Solve:\)

  显然 \(len[s] = n_0 + n_1 + n_2 + 1\)。直接暴力构造即可。左边为全 \(0\),中间为 \(0, 1\),右边为 \(1\) 即可。注意要判断一下 \(n_1\) 的奇偶性。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;

int main(){
    int t; cin >> t;
    while(t --){
        int n0, n1, n2; cin >> n0 >> n1 >> n2;
        string s = "";
        if(n1 == 0){ // 特判
            for(int i = 1; i <= n0; i ++) s += '0';
            for(int i = 1; i <= n2; i ++) s += '1';
            s += n0 ? '0' : '1';
            cout << s << endl;
            continue;
        }
        for(int i = 1; i <= n0; i ++) s += '0';
        if(n1 & 1){
            for(int i = 1; i <= (n1 + 1) / 2; i ++){
                s += '0'; s += '1';
            }
        }else{
            for(int i = 1; i <= n1 / 2; i ++){
                s += '0'; s += '1';
            }
        }
        for(int i = 1; i <= n2; i ++) s += '1';

        if((n1 & 1) == 0) {
            s += '0';
        }
        cout << s << endl;
    }
    return 0;
}

\(\\\)

G. Special Permutation

\(Description:\)

  是否存在一种 \([1, n]\) 的 排列使得相邻两个数差值的绝对值在 \([2, 4]\) 之间?

\(Solve:\)

  显然 \(n < 4\) 是无解的。

  所以我的想法是在 \(n = 4\) 基础上推出其他的。

\[n = 4: (3, 1, 4, 2)\\n = 5: (3, 1, 4, 2, 5)\\n = 6: (3, 1, 4, 6, 2, 5)\\n = 7: (3, 1, 4, 6, 2, 5, 7)\\n = 8: (3, 1, 4, 8, 6, 2, 5, 7) \]

  如果 \(n\) 是奇数,就加在上一项的后面;如果 \(n\) 是偶数,就在中间找一个可以插入的地方,是一定存在的。

  理由,奇数显然是一定可以的,对于偶数的情况下,我们可以发现,对于 \(n = 6\) 的情况,是插入在 \((4, 2)\) 之间的,那么就会存在 \((4, 6)\),那么对于 \(n = 8\) 的情况就可以插入在 \((4, 6)\) 之间,对于 \(n = 10\) 的情况就可以插入在 \((6, 8)\) 之间,依次类推,对于 \(n\) (偶数)来说,可以插入在 \((n - 4, n - 2)\) 之间,所以是一定有解的。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;

vector<int> vec[N]; // vec[i] 代表 n = i 时的合法排列

// 预处理
void init(){
    vec[4] = {3, 1, 4, 2};
    for(int i = 5; i < N; i ++){
        if(i & 1){ // 奇数直接加在上一项后面
            vec[i] = vec[i - 1];
            vec[i].push_back(i);
        }else{
            int mark = 0; // 标记是否加了 i
            for(int j = 0; j < vec[i - 1].size(); j ++){
                int num = vec[i - 1][j];
                vec[i].push_back(num);
                // 判断 vec[i - 1][j], i, vec[i - 1][j + 1] 这样是否合法,合法就插入
                if(!mark && abs(i - num) >= 2 && abs(i - num) <= 4 && j < i - 2 && abs(i - vec[i-1][j+1]) >= 2 && abs(i - vec[i-1][j + 1]) <= 4){
                    vec[i].push_back(i);
                    mark = 1;
                }
            }
        }
    }
}

int main(){
    init();
    int t; cin >> t;
    while(t --){
        int n; cin >> n;
        if(n <= 3) { puts("-1"); continue; }
        for(int i = 0; i < n; i ++) cout << vec[n][i] << " ";
        puts("");
    }
    return 0;
}
posted @ 2020-05-11 10:51  nonameless  阅读(127)  评论(1编辑  收藏  举报