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; }
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; }
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; }
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; }
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; }
以上是关于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) 题解