A-Cancel the Trains
题目描述
Gildong
有一列车系统。从左到右,从下到上分别有100头列车。从每侧出发的列车从 1 到 100 编号,所有列车的速度相同。如图。列车系统可以用二维平面上的坐标表示。每一头列车视为一个点,从底部开始的第 i 头列车最初在 (i,0) ,并将在 T 分钟后到达 (i,T),从左端开始的第 i 列车最初在 (0,i) ,在 T 分钟后到达 (T,i) 。所有列车在 101分钟后到达目的地。
然而,
Gildong
发现,一些在特定时间发车的列车,是存在危险的。这时,有 n 头列车计划从底端发车,m 列车计划从左端发车。如果两列火车同时处于 (x,y) 的位置,那么它们会相撞。因此,Gildong
要求你找出应该取消的最小列车数,以防止所有碰撞发生。
输入格式
每个数据点包含一个或多组数据。第一行包含测试组数t(1≤t≤100)。
每个测试数据包含三行。
第一行两个整数 n 和m(1≤n,m≤100),代表计划从底端出发的列车数和计划从左端出发的列车数。
第二行包含 n 个整数。每个整数代表从底端开始的列车号。这些数字是按严格递增的顺序给出的,介于 1 到 100 之间(含 1 和 100)。
第三行包含 m 个整数。每个整数代表从左端开始的列车号。这些数字是按严格递增的顺序给出的,介于 1 到 100之间(含 1 和 100)。
输出格式
对于每个测试用例,输出一个整数:为了防止所有碰撞,应该取消的最小列车数。
Sample Input
3
1 2
1
3 4
3 2
1 3 4
2 4
9 14
2 7 16 28 33 57 59 86 99
3 9 14 19 25 26 28 35 41 59 85 87 99 100
Sample Output
0
1
3
题目分析
签到题。。。转化为:计算从底端出发和从左端出发的列车具有相同标号大小的个数。
AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
map<int, int>a, b;
int num = 0;
int te;
int n, m;
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> te;
a[te] = 1;
}
for (int i = 0; i < m; i++) {
cin >> te;
b[te] = 1;
}
for (int i = 1; i <= 100; i++) {
if (a[i] && b[i]) {
num++;
}
}
cout << num << endl;
}
return 0;
}
B-Suffix Operations
题目描述
给你一个整数序列,其中有n个元素。你需要对这个序列进行操作。
1 在所有操作开始前,你可以选择一个数,并修改他的值,这个值你可以自己定。本操作无花费。
2 选择一个下标i,将所有下标不小于i的元素加上一个整数x,x可以你自己定。这次操作花费为x的绝对值。
本题给你一个序列,要你求将这个序列中的元素统一,至少花费多少。
输入格式
第一行一个整数,测试数据数量。
对于每个测试数据,第一行一个整数n,元素的个数。接下来一行n个整数,为元素的值。
输出格式
对于每组数据,输出最小花费,占一行。
注意,元素值可能为负数或0。
Sample Input
7
2
1 1
3
-1 0 2
4
99 96 97 95
4
-3 -5 -2 1
6
1 4 3 2 4 1
5
5 0 0 0 5
9
-367741579 319422997 -415264583 -125558838 -300860379 420848004 294512916 -383235489 425814447
Sample Output
0
1
3
4
6
5
2847372102
题目分析
这道题不算难。
先假设不修改任何一个数,那么最终的花费将是整个序列差分数组元素的和mx。接下来去修改某个值,该值与其边上两点的关系有如下两种可能 单调 和 不单调。
使得花费最小的情况是使该点在 左序列右端点 和 右序列左端点 中间,即这三个点满足一个单调关系。
(1 )单调时:满足上述情况。(2)不单调时:需要使该点满足上述情况。
所以,从第二个点遍历到第N-1个点,使它们满足上述情况并修改最后的mx,
mx = min(mx, ans - abs(a[i] - a[i - 1]) - abs(a[i] - a[i + 1]) + abs(a[i - 1] - a[i + 1]));
对于整个序列左端点和右端点进行特判,
mx = min(mx, ans - abs(a[1] - a[2])); //左端点特判
mx = min(mx, ans - abs(a[n - 1] - a[n])); //右端点特判
最后,mx即为所求最终花费。
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
ll a[200000 + 10]; //a[]数组存放序列元素
int b[200000 + 10];//b[]存差分数组
int main()
{
int t;//表示有t组数据
cin >> t;
while (t--)
{
ll n; //每组数据n个数
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
ll ans = 0; //统计差分数组的总和
for (int i = 2; i <= n; i++)
{
b[i] = abs(a[i] - a[i - 1]);
ans += b[i];
}
ll mx = 1e18;
for (int i = 2; i < n; i++)
{
mx = min(mx, ans - abs(a[i] - a[i - 1]) - abs(a[i] - a[i + 1]) + abs(a[i - 1] - a[i + 1]));
}
mx = min(mx, ans - abs(a[1] - a[2])); //左端点特判
mx = min(mx, ans - abs(a[n - 1] - a[n])); //右端点特判
cout << mx << endl;
}
return 0;
}
G-Buy the String
题目描述
给出四个整数 n,c0,c1 和 h ,以及一个长度为 n 的字符串 s ,且 s 仅由 0 和 1组成。你可以每次以 h 的花费修改字符串中的一个字符。在经过一些修改后,你需要买下这个字符串,其中字符 0需要花费 c0 ,字符 1 需要花费 c1 。求最小花费。
Sample Input
6
3 1 1 1
100
5 10 100 1
01010
5 10 1 1
11111
5 1 10 1
11111
12 2 1 10
101110110101
2 100 1 10
00
Sample Output
3
52
5
10
16
22
题目分析
签到题。。。如果c0>c1+h,就将0换成1,如果c1>c0+h,就将1换成0。
AC代码
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
int sum = 0;
int num0 = 0, num1 = 0;//num0为0的个数,num1为1的个数
int n, c0, c1, h;
cin >> n >> c0 >> c1 >> h; //c0为购买一个0的花费,c1为购买一个1的花费
string s;
cin >> s;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '0') num0++;
else num1++;
}
//cout << num0 << " " << num1 << endl;
if (c0 > h + c1) sum += (h + c1) * num0;
else sum += c0 * num0;
if (c1 > h + c0) sum += (h + c0) * num1;
else sum += c1 * num1;
cout << sum << endl;
}
return 0;
}
H -Sum of Medians
题目描述
题目翻译
给定n×k 个正整数,要求将这些数分成 k 组,每组 n 个,并且希望每一组第 ⌈2n⌉ 大的数的和尽可能大,请求出这个和。
Sample Input
6
2 4
0 24 34 58 62 64 69 78
2 2
27 61 81 91
4 3
2 4 16 18 21 27 36 53 82 91 92 95
3 4
3 11 12 22 33 35 38 67 69 71 94 99
2 1
11 41
3 3
1 1 1 1 1 1 1 1 1
Sample Output
165
108
145
234
11
3
题目分析
这道题也不算难。
先求出题意描述的中位数的位置Z(可以用上次学到的向上取整的表达式)。用前面(Z-1)*k个数one by one填充k组中位数前的位置,从(Z-1)*k+1个数开始,每隔n-Z+1取数,并将这些数相加,即为满足题意的最大中位数之和。
AC代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
ll t;
cin >> t;
while (t--)
{
ll temp;
vector<int>w;
ll n, k;
cin >> n >> k;
w.push_back(-1);//先存入一个值,使得后面n*k个数中第一个数的下标为1
for (ll i = 0; i < n * k; i++) {
cin >> temp; w.push_back(temp);
}
ll zhong = (n - 1) / 2 + 1; //找到题意中位数的位置,这里用向上取整的方法。
ll sum = 0;
for (ll j = (zhong - 1) * k + 1; j <= n * k; j += n - zhong + 1) {
sum += w[j];
}
cout << sum << endl;
}
return 0;
}
I -Binary Table (Easy Version)
题目描述
题意
给定一个 n×m 的 01 矩阵,每次操作可以将某个 2×2 的矩阵内的 3 个数取反,请在 3×n×m 步内将矩阵变为全 0。
题目分析
我们可以每次只改变一个点。如何做到呢?
? 1
? ?
我们在这个矩阵中找到所有 ? 点作为中心 ,依次对其它三个点进行取反: 第一次,找到左上角的 ? ,对另外三个点进行取反。
? 0
¿ ¿
反问号¿表示原来的?取反后的值。
第二次:找到左下角的 ¿ ,对另外三个点进行取反。
¿ 1
¿ ?
第三次:找到右下角的 ? ,对另外三个点进行取反。
? 0
? ?
这样,原来的 1 就变成了 0,并且其它点不受影响,也就是说,我们每找到一个 1 , 就可以把它放到一个 2∗2 的矩阵里,以另外三个点作为中心(即不取反的那个,无论是 0 还是 1)对与其互斥的三个点取反,就能达到目标,即使矩阵全部都是 1 , 也能在 3nm 步内完成。
但是每次把“1”的位置作为2*2矩阵的哪个位置是需要讨论的,如下所示。
⭐的位置是“1”在2*2矩阵的位置。分为四种情况:
AC代码
#include<bits/stdc++.h>
using namespace std;
int main() {
int t; //t组数据
cin >> t;
while (t--)
{
vector<string>srr;
int n, m; //n行m列
cin >> n >> m;
string s;
for (int i = 0; i < n; i++) {
cin >> s;
srr.push_back(s);
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (srr[i][j] == '1') {
ans += 3;
}
}
}
cout << ans << endl;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < m - 1; j++) {
if (srr[i][j] == '1') {
cout << i + 1 << " " << j + 1 << " " << i + 2 << " " << j + 1 << " " << i + 2 << " " << j + 2 << endl;
cout << i + 1 << " " << j + 1 << " " << i + 2 << " " << j + 2 << " " << i + 1<< " " << j + 2 << endl;
cout << i + 1 << " " << j + 1<< " " << i + 1 << " " << j + 2 << " " << i + 2 << " " << j + 1 << endl;
}
}
}
for (int j = 0;j < m - 1; j++) {
if (srr[n - 1][j] == '1') {
cout << n - 1 + 1 << " " << j + 1 << " " << n - 1 << " " << j + 1 << " " << n - 1 << " " << j+2 << endl;
cout << n - 1 + 1 << " " << j + 1 << " " << n - 1+1 << " " << j +2 << " " << n - 1<< " " << j+2 << endl;
cout << n - 1 + 1 << " " << j + 1 << " " << n - 1 << " " << j + 1 << " " << n - 1+1 << " " << j+2<< endl;
}
}
for (int i = 0; i < n - 1; i++) {
if (srr[i][m - 1] == '1') {
cout << i + 1 << " " << m - 1 + 1 << " " << i + 2 << " " << m - 1 + 1 << " " << i + 2 << " " << m - 1 << endl;
cout << i + 1 << " " << m - 1 + 1 << " " << i + 1 << " " << m - 1 << " " << i + 2 << " " << m - 1 << endl;
cout << i + 1 << " " << m - 1 + 1 << " " << i + 1 << " " << m - 1 << " " << i + 2 << " " << m - 1+1 << endl;
}
}
if (srr[n - 1][m - 1] == '1') {
cout << n - 1 + 1 << " " << m - 1 + 1 << " " << n - 1 << " " << m - 1 + 1 << " "<<n - 1 << " " << m - 1 << endl;
cout << n - 1 + 1 << " " << m - 1 + 1 << " " << n - 1+1 << " " << m - 1 << " " << n - 1 << " " << m - 1 << endl;
cout << n - 1 + 1 << " " << m - 1 +1 << " " << n - 1+1 << " " << m - 1 << " " << n - 1 << " " << m - 1 +1<< endl;
}
}
return 0;
}