A. Most Unstable Array
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;
const int INF = 0x3f3f3f3f;
int main() {
int t; cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
if (n >= 3)
cout << 2 * m << endl;
else if (n == 2)
cout << m << endl;
else
cout << 0 << endl;
}
}
B. Two Arrays And Swaps
题意:
给你两个长度为n的数组a,b,每一次操作可以交换a,b数组中的一对数字,一共可以交换小于等于k次
题解:
a的前k小交换b的前k大,注意交换的时候a数组的元素必须小于b数组的元素
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 33;
int a[maxn], b[maxn];
int main() {
int t; cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
for (int i = 1; i <= n; i++)
scanf("%d", b + i);
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
int sum = 0;
for (int i = k + 1; i <= n; i++)
sum += a[i];
for (int i = 1; i <= k; i++) {
if (a[i] > b[n - i + 1])
sum += a[i];
else
sum += b[n - i + 1];
}
cout << sum << endl;
}
}
C. Board Moves
题意:有n*n个格子,每个格子上有一个元素,每一次操作可以将一个格子移动到它左上,左下,右上,右下,上,左,下,右八个格子,问最少需要多少次才能够将所有格子上的元素移到同一个格子,n一定是奇数
题解:首先很明显可以移动到最中间的格子。然后这道题的答案可以全部先预处理出来然后一次作答,因为n=x的答案可以从n=x-2的答案中推得。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<algorithm>
#include<stack>
#define ll long long int
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 5e5 + 7;
ll ans[maxn];
int main() {
int t; cin >> t;
ans[1] = 0;
for (ll i = 3; i <= 5e5; i += 2) {
// (i/2)表示当前层的数字
ans[i] = ans[i - 2] + 4 *(i - 1) * (i / 2);
}
while (t--) {
int n; cin >> n;
cout << ans[n] << endl;
}
return 0;
}
D. Constructing the Array
题意:
好难翻译不翻了。。
题解:
优先队列,长度长的先处理
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<algorithm>
#include<stack>
#define ll long long
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5 + 7;
int a[maxn], val;
struct node {
int l, r, val;
bool operator< (const node& e)const {
return val == e.val ? l > e.l : val < e.val;
}
bool operator> (const node& e)const {
return val == e.val ? l > e.l : val > e.val;
}
};
priority_queue<node, vector<node>, less<node> >Q;
int main() {
int t; cin >> t;
while (t--) {
int n; cin >> n;
val = 0;
Q.push(node{ 1,n,n });
node now;
while (!Q.empty()) {
now = Q.top();
Q.pop();
int mid = now.l + now.r >> 1;
a[mid] = ++val;
if (now.val == 2)
Q.push(node{ mid + 1,now.r,1 });
else if (now.val > 2) {
Q.push(node{ now.l,mid - 1,mid - now.l });
Q.push(node{ mid + 1,now.r,now.r - mid });
}
}
for (int i = 1; i <= n; i++)
printf("%d ", a[i]);
putchar('\n');
}
return 0;
}
E. K-periodic Garland
题意:
给一串长度为n的串,里面只有0和1,每次操作可以将某一位的0变成1或者1变成0 ,操作的最后需要串里面两个1之间有k-1个0,问最少需要操作多少次
题解:
对于某一位都只有两种选择,填0或者填1,设
dp[i][0]:第i位填0,前面都合法,最小需要的操作数
dp[i][1]:第i位填1,前面都合法,最小需要的操作数
因为本题对于 0001000这样的串也算是合法的,所以对于每一位都可以考虑当前位为1,然后前面全是0
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<algorithm>
#include<stack>
#define ll long long
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1e6 + 7;
int dp[maxn][2];
int sum[maxn];
char s[maxn];
int main() {
int t; cin >> t;
int cnt = 0;
while (t--) {
int n, k;
cin >> n >> k;
cin >> (s + 1);
for (int i = 1; i <= n; i++) {
if (s[i] == '1')
sum[i] = sum[i - 1] + 1;
else
sum[i] = sum[i - 1];
}
for (int i = 1; i <= n; i++) {
int las = max(0, i - k);
//当前位是0
dp[i][0] = min(dp[i - 1][1], dp[i - 1][0]) + (s[i] == '1');
//当前位是1,可以考虑前面都为0,或者k个之前是1
dp[i][1] = min(dp[las][1] + sum[i - 1] - sum[las], sum[i - 1]) + (s[i] == '0');
}
cout << min(dp[n][0], dp[n][1]) << endl;
}
}
F. Decreasing Heights
题意:n*m的地图上每个格子都有它的高度a , 对于第i,j格,你可以向右边走或者下面走,还有另外一个限制条件,每一次只能向比当前高度大1的格子走。你可以进行操作,每次操作将一个格子的高度下降1,问最少需要进行多少次操作可以使你从左上角的格子走到右下角的格子。
题解:
对于4*3的地图:
100 101 102
-4 -4 103
-3 -3 104
-10 -10 2
当你走到(3,3)的时候,你的最优选择从(2,3)来
但是当你走到(4,3)的时候你会发现‘(3,3)的最优选择应该来自(3,2)
假如是直接按照dp[i][j]表示走到(i,j)格子的最优情况,然后往右边和下面格子递推,这样的递推方式是错的。
这个时候应该枚举不变点,就是从左上到右下的路径上总会出现一个点不需要更改高度的,枚举这样的点,然后以这个点为中心递推回左上角和右下角
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
#include<algorithm>
#include<stack>
#define ll long long
#define ull unsigned long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 107;
ll dp[maxn][maxn], hei[maxn][maxn];
int n, m;
//逆向推到(1,1)
ll DP1(int x, int y) {
for (int i = x; i; i--) {
for (int j = y; j; j--) {
if (i == x && j == y)
continue;
ll to = hei[x][y] - (x - i + y - j);
if (hei[i][j] < to) {
dp[i][j] = 1e18;
continue;
}
if (i == x)
dp[i][j] = dp[i][j + 1] + hei[i][j] - to;
else if (j == y)
dp[i][j] = dp[i + 1][j] + hei[i][j] - to;
else
dp[i][j] = min(dp[i][j + 1], dp[i + 1][j]) + hei[i][j] - to;
}
}
return dp[1][1];
}
//顺推到dp[n][m]
ll DP2(int x, int y) {
for (int i = x; i <= n; i++) {
for (int j = y; j <= m; j++) {
if (i == x && j == y)
continue;
ll to = hei[x][y] + (i - x + j - y);
if (hei[i][j] < to) {
dp[i][j] = 1e18;
continue;
}
if (i == x)
dp[i][j] = dp[i][j - 1] + hei[i][j] - to;
else if (j == y)
dp[i][j] = dp[i - 1][j] + hei[i][j] - to;
else
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + hei[i][j] - to;
}
}
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 >> hei[i][j];
ll ans = 1e18;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
//枚举不变点
dp[i][j] = 0;
ans = min(ans, DP1(i, j) + DP2(i, j));
}
}
cout << ans << endl;
}
return 0;
}
’