Codeforces Round #642 (Div. 3) 题解

Posted lyfer233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #642 (Div. 3) 题解相关的知识,希望对你有一定的参考价值。

这场的题目中规中矩,偏重DP类型的。

A题 Most Unstable Array

题意:

让你构造一个长度为n,所有数加和为m的序列,并且使相邻两个数之差的绝对值求和值最大,输出这个最大值。(同时每个数非负)

思路:

显然就像样例中给的一样,我们构造一个长度为n的序列的最方便的方法就是 奇数项都是0,偶数项加和起来为m。而在这种方法下也即是最大值,因为此时 所有偶数项与奇数项之差的绝对值之和为 2 * m,无论调换哪两个的顺序都会使结果变坏。

技术图片
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
int t;
ll n,m;
 
int main(){
    cin >> t;
    while(t--){
        cin >> n >> m;
        if(n == 1) puts("0");
        else if(n == 2) printf("%lld
", m);
        else printf("%lld
", m * 2);
    }    
    return 0;
}
AC Code

 

B题 Two Arrays And Swaps

题意:

给你长度n的A数组和B数组,你可以执行不超过K次操作——将B数组的bi与A数组的aj进行交换。 求A数组的最大值

思路:

这个很显然就是一个贪心题目,我们只需要选出B数组最大的K个数看能否与A数组最小的K个数进行交换即可。

技术图片
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
int t;
int n, k;
int a[33], b[33];
 
int main(){
    cin >> t;
    while(t--){
        cin >> n >> k;
        for(int i = 1; i <= n; i++) cin >> a[i];
        for(int i = 1; i <= n; i++) cin >> b[i];
        sort(a + 1, a + 1 + n);
        sort(b + 1, b + 1 + n);
        reverse(b + 1, b + 1 + n);
        int Pos = 1;
        for(int i = 1; i <= k; i++){
            if(b[Pos] > a[i]){
                swap(b[Pos], a[i]);
                Pos++;
            }
            else break;
        }
        int Sum = 0;
        for(int i = 1; i <= n; i++) Sum += a[i];
        cout << Sum << endl;
    }    
    return 0;
}
AC Code

 

C题 Board Moves

题意:

给出一个n*n的棋盘(n是奇数),每个棋子都可以朝相邻的8个方向自由移动(棋子可以重叠),要求使得所有棋子都移动到同一个方格中的最少的移动次数是多少?

思路:

模拟n = 1, 3, 5, 7,... 就可以发现这是一个公式题目。手推公式就可以了。

技术图片
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
int t, n;
ll ans[555555];
 
int main(){
    for(ll i = 3; i <= 500000; i+=2) ans[i] = ans[i - 2] + (i - 1) / 2 * (i - 1) * 4;
    cin >> t;
    while(t--){
        cin >> n;
        cout << ans[n] << endl;
    }
    return 0;
}
AC Code

 

D题 Constructing the Array

题意:

给出一个长度为n的区间,按从1~n的顺序,每次选取最长区间的中点填上数字。长度相同则选靠前的。

思路:

数据结构题目,因为每次都要取最长区间。所以我们需要用一个优先队列维护信息。

每次选取长度最长的,长度相同则区间L越小越好。

技术图片
#include <bits/stdc++.h>
using namespace std;
 
typedef long long ll;
struct node{
    int l, r, len;
    bool operator < (const node & a) const {
        if(len != a.len) return len < a.len;
        else return l > a.l;
    }
};
int t, Mid;
int n, ans[200005];
 
int main(){
    cin >> t;
    while(t--){
        cin >> n;
        priority_queue<node>q;
        node Start;
        Start.l = 1;
        Start.r = n;
        Start.len = n;
        q.push(Start);
        for(int i = 1;i <= n; i++){
            node Now = q.top();
            q.pop();
            if(Now.len % 2 == 0) Mid = (Now.l + Now.r - 1) / 2;
            else Mid = (Now.l + Now.r) / 2;
            
            ans[Mid] = i;
            node First = Now;
            First.r = Mid - 1;
            First.len = First.r - First.l + 1;
            if(First.len >= 1) q.push(First);
            
            node Second = Now;
            Second.l = Mid + 1;
            Second.len = Second.r - Second.l + 1;
            if(Second.len >= 1) q.push(Second);
        }
        for(int i = 1; i <= n; i++) printf("%d ",ans[i]);
        printf("
");
    }    
    return 0;
}
AC Code

 

E题 K-periodic Garland

题意:

给出一个长度为n的01串,要求每两个1之间的间距必须为k。(即两个1之间隔k-1个0)求最少要反转几个位置才能满足要求。

思路:

这个题目的主要难点在于

F题 Decreasing Heights

题意:

给出一个n*m的棋盘,每个位置都有一个高度。你可以选择任意一个位置将其高度降低X(只能降低不能增加),最后你的总花费就是所有位置降低X的总和。你的目标是从(1,1)到(n,m)找到一条高度单调不下降的路径。求满足条件的最少花费!保证一定有解

思路:

本道题目主要在于发现一条重要的性质:在从(1,1)到(n,m)的路径中,每条路径上最会有一个位置保持不变(也就是基准点)。 假设当前路径且存在唯一一个不动点高度为Y,如果降低这个唯一不动点的高度,则这条路径上所有的高度也得相应降低,故不符合最优解。

还需要另外一条性质:只要确定了不动点的高度,那么(1,1)点的高度也显然是固定的。 这个也很显然,因为是从(1,1)出发的,如果想要最优的话那么必然是从不动点的高度Y,一步一步减1倒推到(1,1)的高度。

也就是我们如果知道不动点的高度那么(1,1)的高度也可以确定,如果(1,1)点确定那么整个棋盘上所有点的高度也可以确定。 因为如果(1,1)高度为H,则其相邻的点(1,2)和(2,1)高度应该为H+1(如果可以降低到H+1的前提下),相应可以递推到(n,m)的高度也是确定的,也就是可以递推计算所有位置降低高低的cost是多少。

所以思路就很明显了,我们不能确定那个唯一不动点在哪个位置,所以我们只能枚举每个位置是唯一不动点时此时花费是多少,最后取个最小值即可。

还有两个注意细节,一是如果当前这个不动点的高度为Y,计算出(1,1)点的高度为H,且 Y < H则说明这种情况不成立,因为题目要求不下降。

技术图片
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const ll INF = 1e18;

int t;
ll dp[105][105];
ll num[105][105];

int main(){
    cin >> t;
    while(t--){
        int n, m;
        cin >> n >> m;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= m; j++)
                cin >> num[i][j];
        
        ll ans = INF;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                
                ll now = num[i][j] - i - j;
                if(now > num[1][1]) continue;
                 //Start
                for(int x = 0; x <= n; x++){
                    for(int y = 0; y <= m; y++){
                        dp[x][y] = INF;
                    }
                }
                
                dp[1][1] = num[1][1] - now;
                
                for(int x = 1; x <= n; x++){
                    for(int y = 1; y <= m; y++){
                        ll cost = num[x][y] - x - y - now;
                        if(cost < 0) continue;
                        dp[x][y] = min(dp[x][y], dp[x - 1][y] + cost);
                        dp[x][y] = min(dp[x][y], dp[x][y - 1] + cost);
                    }
                }
                ans = min(ans, dp[n][m]);
            }
        }
        cout << ans - 2 << endl;
    }
    return 0;
}
AC Code

 

以上是关于Codeforces Round #642 (Div. 3) 题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #642 (Div. 3)

Codeforces Round #642 (Div. 3)

Codeforces Round #642 (Div. 3)

Codeforces Round #642 (Div. 3) 题解

Codeforces Round #642 (Div. 3)A~D

Codeforces Round #642 (Div. 3)A~D