返回顶部

Codeforces Round #642 (Div. 3)【ABCDEF】(题解)

涵盖知识点:思维、dp

比赛链接:传送门

A - Most Unstable Array

题意: 要求构造长度为\(n\)的非负数组使得和为\(m\)\(\sum\limits_{i=1}^{n-1} |a_i - a_{i+1}|\)最大化
题解: \(0,m,0,0,0,0\ldots\)。特判\(1,2\)
Accept Code:

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

int main(){
    int t;cin>>t;
    while(t--) {
        int n, m;
        cin >> n >> m;
        if (n >= 3)cout << 2 * m << "\n";
        else cout << m * (n - 1) << "\n";
    }
    return 0;
}

B - Two Arrays And Swaps

题意: 至多\(k\)次机会可以互换数组\(a,b\)的任何一个数。求\(a\)的最大和。
题解: \(a\)最小的换\(b\)最大的,直到\(a\)全部比\(b\)大。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
int a[maxn],b[maxn];
int main(){
    int t;cin>>t;
    while(t--) {
        int n,k;
        cin>>n>>k;
        int sum=0;
        for(int i=0;i<n;i++)cin>>a[i],sum+=a[i];
        for(int i=0;i<n;i++)cin>>b[i];
        sort(a,a+n);
        sort(b,b+n);
        reverse(b,b+n);
        for(int i=0;i<k;i++){
            if(a[i]>=b[i])break;
            sum+=b[i]-a[i];
        }
        cout<<sum<<"\n";
    }
    return 0;
}

C - Board Moves

题意: \(n\times n\)的方格依次标号(\(n\)是奇数)。每次操作可以将一个方格中的一个数移动到与其相邻的方格(包括斜对角)。求最少几次操作使得某个方格含有全部数字。
题解: 全移到中间。每一圈距离中心的距离相等。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=110;
typedef long long ll;
int main(){
    int t;cin>>t;
    while(t--) {
        int n;
        cin>>n;
        ll ans=0;
        for(int i=1;i<=n/2;i++)ans+=1ll*i*i*8;
        cout<<ans<<"\n";
    }
    return 0;
}

D - Constructing the Array

题意: 给定初始全0数组。现在对于每次操作,要求找到最长的全0子串(相等长度选左边那个)。将其中间(偶数偏左)的数赋值为当前操作的次数。
题解: 优先队列维护。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
int ans[maxn];
struct Node{
    int l,r;
    bool operator <(const Node &b)const{
        return b.r-b.l!=r-l?l-r>b.l-b.r:l>b.l;
    }
    Node()=default;
    Node(int _l,int _r){l=_l,r=_r;}
};
priority_queue<Node> q;
int main(){
    int t;cin>>t;
    while(t--) {
        memset(ans,0,sizeof ans);
        int n;
        cin>>n;
        q.push(Node{1,n});
        int cnt=0;
        while(!q.empty()){
            Node tmp=q.top();
            q.pop();
            int mid=(tmp.l+tmp.r)/2;
            ans[mid]=++cnt;
            if(tmp.l<mid)q.push(Node(tmp.l,mid-1));
            if(tmp.r>mid)q.push(Node(mid+1,tmp.r));
        }
        for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
        cout<<"\n";
    }
    return 0;
}

E - K-periodic Garland

题意: 给定\(01\)串,每次操作可以使\(0\)变为\(1\)或者\(1\)变成\(0\)。求最少几次操作使得所有的相邻\(1\)的间隔为\(k\)
题解: 首先我们计算出原串中的\(1\)的个数为\(cnt\)。然后枚举\(mod\ k\)意义下的每一位为\(1\)的情况所需个数。注意如果一开始或某个位置需要从\(0\)变为\(1\)的次数大于之前原本是\(1\)的个数,我们可以认为前面的序列全\(0\)。这样次数更小一些。
Accept Code:

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

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        string s;
        cin >> s;
        int cnt=count(s.begin(),s.end(),'1');
        ll ans = 1e18;
        for (int mod = 0; mod < k; mod++) {
            ll here = cnt;
            ll delta = 0;
            for (int i = mod; i < n; i += k) {
                if (s[i] == '0') delta++;
                else delta--;
                delta = min(delta, 0ll);
                ans = min(ans, here + delta);
            }
        }
        cout << ans << '\n';
    }
}

F - Decreasing Heights

题意: \(n\times m\)的地图每个位置都有一个值,每次只能向下或者向右走,且对应的方格的值必须为当前方格的值加\(1\).现在每次操作可以使得一个方格的值减\(1\)。问最少几次操作可以使得从\((1,1)\)走到\((n,n)\)
题解: 通过枚举每一个位置的现有值,我们可以确定当前地图所有合法路径应该存在的值。再dp一下就行了。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
ll a[110][110],dp[110][110];
ll calc(ll st){
    for(int i=0;i<=n;i++){
        for(int j=0;j<=m;j++)
            dp[i][j]=1e18;
    }
    if (a[1][1]>=st) dp[1][1]=a[1][1]-st;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if ((i==1) && (j==1)) continue;
            if (a[i][j]>=(st+i+j-2)){
                ll now=a[i][j]-(st+i+j-2);
                dp[i][j]=min(dp[i-1][j],dp[i][j-1])+now;
            }
        }
    }
    return dp[n][m];
}

int main(){
    int t;cin>>t;
    while (t--){
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                cin>>a[i][j];
        }
        ll ans=1e18;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                ans=min(calc(a[i][j]-(i+j-2)),ans);
        }
        cout<<ans<<"\n";
    }
    return 0;
}

posted @ 2020-05-15 17:54  Charles1999  阅读(152)  评论(0编辑  收藏  举报