Codeforces Round #519 题解

A. Elections

题意概述

给出 \(a_1, \ldots, a_n\),求最小的 \(k (k \ge \max a_i)\), 使得 \(\sum_{i=1}^n a_i < \sum_{i=1}^n (k-a_i)\) 原题链接

解题思路

数据范围小,直接枚举就好了

代码

#include <bits/stdc++.h>

using namespace std;

int main() {
        ios::sync_with_stdio(false);
        int n;
        cin >> n;
        long long sum = 0;
        int mx = 0;
        for(int i=0; i<n; i++) {
                int x;
                cin >> x;
                sum+=x;
                if(x>mx) mx = x;
        }
        int start = sum*2/n;
        if(start < mx) start = mx;

        for(int i=start; ;i++) {
                if(i*n > sum*2) {cout << i << endl;break;}
        }
        return 0;
}

B. Lost Array

题意概述

有一个数组 \(x_0, x_1, \ldots, x_{k-1}\) . 由它可以得到另一个数组 \[ a_i=\left\{\begin{array}{ll} 0& i=0,\\ x_{(i-1)\bmod k} + a_{i-1}& 1 \le i \le n \end{array}\right. \] 现给出数组 \(a\),求数组 \(x\) 的所有可能长度 原题链接

解题思路

根据公式可发现,\(a_i - a_{i-1} = x_{(i-1)\bmod k}\) , 若 \(k = n\) 则得到一个可行的 $ a $ , 再枚举 \(k\),判断在 \(a\) 中是否 \(k\)个一组循环即可

代码

#include <bits/stdc++.h>

using namespace std;

int a[2000],b[2000];
int main() {
        ios::sync_with_stdio(false);
        int n;
        cin >> n;
        for(int i=1; i<=n; i++) {
                cin >> a[i];
                b[i] = a[i]-a[i-1];
        }

        vector<int > ans;

        for(int i=1; i<=n; i++){
                bool flag = true;
                for(int j=1; j<=i; j++) {
                        int ti = n/i; if(n%i) ti++;
                        for(int k=0; k<ti; k++) {
                                if((k+1)*i+j<=n){
                                if(b[k*i+j]==b[(k+1)*i+j]) {

                                }else {
                                        flag = false;
                                        break;
                                }
                                }
                        }
                        if(flag==false) break;
                }
                if(flag) ans.push_back(i);
        }
        cout << ans.size() << endl;
        for(auto i : ans) cout << i << " ";
        return 0;
}

C. Smallest Word

题意概述

给出一个只包含字符 a 和 b 的串 s,对于从左到右每一个前缀,都可以选择进行翻转或者不翻转,使得最后这个字符串的字典序最小原题链接

解题思路

通过翻转一定可以使得所有的a在前面,b在后面,从而使字典序最小。
粗略证明:

  • 假设当前的前缀子串满足字符 'a' 和 'b' 分别在该子串的两端( 如[aabb], [baa]),那么下一个前缀子串也一定满足这个性质(如果不满足,可通过翻转当前的前缀子串来使下一个前缀子串满足, 如[aaabb]a 翻转 [bbaaa]a)
  • 其中第一个前缀子串一定满足该性质,递推得证

所以只需要找到由右至左第一个 'a' 的位置,然后从它开始向左遍历,每当 \(s_i \neq s_{i+1}\) 那么需要翻转,否则不翻转

代码

#include <bits/stdc++.h>

using namespace std;

char s[2000];
int ans[2000];
int main() {
        ios::sync_with_stdio(false);
        cin >> s;
        int pos = -1;
        for(int i=strlen(s)-1; i>=0; i--) {
                if(s[i] == 'a') {
                        pos = i;
                        break;
                }
        }
        if(pos==-1) {

        }
        ans[pos] = 1;
        for(int i=pos-1; i>=0; i--) {
                if(s[i] != s[i+1]) ans[i] = 1;
                else ans[i] = 0;
        }
        for(int i=0; i<strlen(s); i++) {
                cout << ans[i] << " ";
        }
        return 0;
}

D. Mysterious Crime

题意概述

给出 m 组 1~n 的排列,每一组选择删除一些前缀和后缀,使得所有组剩下的部分的数字以及剩下的数字的顺序都相同,求有多少种删除方法。

解题思路

首先至少有 n 种方法,即每组都删到只剩一个相同的数字为止
当某一个连续区间在 m 组中都出现时,答案+1
所以可以在每一组中,记录某个数的下一个数。当这个关系在其他组不成立时,则这一组数字对答案没有贡献
当连续区间较大时,区间长度每+1,答案 += 当前区间长度
原题链接
(表述不清晰。留坑)

代码

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e5+7;

int a[maxn],f[maxn];

int main() {
        ios::sync_with_stdio(false);
        int n, m;
        cin >> n >> m;
        for(int i=1; i<=n; i++) {
                cin >> a[i];
                f[a[i-1]] = a[i];
        }f[a[n]] = n+1;
        for(int i=1; i<m; i++) {
                for(int i=1; i<=n; i++) {
                        cin >> a[i];
                        if((i-1) && f[a[i-1]]!=a[i]) f[a[i-1]]=-1;
                } if(f[a[n]] != n+1) f[a[n]]=-1;
        }
        int len = 0;long long ans = 0;
        for(int i=1; i<n; i++) {
                if(f[a[i]] > 0)
                if(f[a[i-1]] > 0) {
                        len ++;
                        ans += len;
                } else {
                        len = 1;
                        ans += len;
                }
        }
        cout << n+ans << endl;
        return 0;
}

E. Train Hard, Win Easy

题意概述

留坑原题链接

解题思路

留坑

代码

#include <bits/stdc++.h>

using namespace std;

const int maxn=3e5+7;

int f[maxn];

struct __ {
        long long x, y, id;
        bool operator<(const __ & b) const {
                return (x-y) > (b.x-b.y);
        }
}a[maxn];

long long sum[maxn];

int main() {
        ios::sync_with_stdio(false);
        int n, m;
        cin >> n >> m;
        for(int i=0; i<n; i++) {
                cin >> a[i].x >> a[i].y;
                a[i].id = i;
        }
        sort(a, a+n);
        for(int i=0; i<n; i++) {
                f[a[i].id] = i;
        }
        long long s=0;
        for(int i=0; i<n; i++) {
                sum[i] = a[i].x*i+(n-1-i)*a[i].y;
        }
        for(int i=1; i<n; i++) {
                s+=a[i-1].y;
                sum[i]+=s;
        }
        s = 0;
        for(int i=n-2; i>=0; i--) {
                s+=a[i+1].x;
                sum[i]+=s;
        }
        for(int i=0; i<m; i++ ) {
                int s, t;
                cin >> s1 >> t1;
                s1--;t1--;
                s1 = f[s1];
                t1 = f[t1];
                long long sub = 0;
                if(a[s1].x+a[t1].y<a[s1].y+a[t1].x){
                        sub = a[s1].x + a[t1].y;
                }else {
                        sub = a[t1].x + a[s1].y;
                }
                sum[s1] -= sub;
                sum[t1] -= sub;
        }
        for(int i=0; i<n; i++) {
                cout << sum[f[i]] << " ";
        }
        return 0;
}

F. Make It One

题意概述

留坑赶紧补了

解题思路

留坑

代码

留坑

G. Speckled Band

题意概述

深渊巨坑 有生之年

解题思路

深渊巨坑

代码

深渊巨坑

转载于:https://www.cnblogs.com/wfwf/p/9870381.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值