2024 暑假友谊赛-热身1
2024.7.11 14:00————17:00
过题数3/9
补题数5/9
- AtCoder abc079_d
- AtCoder arc100_a
- AtCoder arc099_a
- AtCoder arc100_b
- CodeForces 1808C
- CodeForces 1547E
- CodeForces 1107C
- AtCoder arc102_b
- AtCoder abc297_g
A - Wall
Floyd算法,当时想到了不过写错了一点,17/19,acm赛制一分没有。后来改用dfs,太久没写了导致dfs也写不出来,后来没过。赛后补题用的是Floyd算法,有时间再用dfs。
题解:
给定二维数组c,代表从数字i变成j所需要的能量,给出一个h行w列的数组a,要求把a中所有数字变成1所需的最小能量。
数据范围不大,直接floyd枚举即可。具体见注释。
代码:
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define int long long
int h,w;
int c[10][10];
int a[205][205];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> h >> w;
for (int i = 0; i <= 9; i++) {
for (int j= 0; j <= 9; j++) {
cin >> c[i][j];
}
}
for (int k = 0; k <= 9; k++) {
for (int i = 0; i <= 9; i++) {
for (int j = 0; j <= 9; j++) {
c[i][j] = std::min(c[i][j], c[i][k] + c[k][j]);
}
}
}//Floyd算法,k注意在外侧即可
int ans = 0;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
cin >> a[i][j];
if(a[i][j]!= -1) {
ans += c[a[i][j]][1];
}
}
}
cout << ans << endl;
return 0;
}
B - Linear Approximation
额很有趣的一道题吧,最近刚好学了三分,想用三分写但是,一直过不了,改了很久还是过不了,后来是数学思维求解的。
继续补题中,改了个三分代码,ac的那种
题解:
给出一个包含n个数字的数组a,求b为多少时伤心值最小。
三分思想很简单,l从-1e9,r从1e9,一直取俩点并舍去不合适区间,直到剩下一些些的时候直接便利即可,只有五十分,不知道错哪了,具体见注释。
数学思维因为取点最后一定是在俩点中间,所以取最中点与取中间任意一点相等,直接取存在的中点即可。
代码:
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define int long long
int n;
int a[200005];
int b[200005];
int check(int x) {
int res = 0;
for(int i = 1; i <= n; i++) {
res += abs(a[i]-(i+x));
}
return res;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] = a[i] - i;
}sort(a+1,a+n+1);
int res = a[n/2+1];
int ans = 0;
for (int i = 1; i <= n; i++) {
ans += abs(a[i]-res);
}
cout << ans << endl;
// int l = -1000000005, r = 1e9+10;
// while (r - l > 50) {
// int mid1 = l+(r-l)/3;
// int mid2 = r-(r-l)/3;
// if(check(mid1) > check(mid2))l = mid1-1;
// else r = mid2+1;
// }
//
// int mi = 1e9+5;
// for (int i = l; i <= r; i++) {
// cout << check(i) << "asd" << i << ' ';
// if(check(i) < mi)mi = check(i);
// }
// cout << mi << endl;
// 错误的长长的三分代码
return 0;
}
//已AC
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define int long long
int n;
int a[200005];
int check(int x) {
int res = 0;
for(int i = 1; i <= n; i++) {
res += abs(a[i]-x);
}
return res;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] = a[i] - i;
}sort(a+1,a+n+1);
int l = -1e12, r = 1e12+10;
int ans = 4e18;
for (int i = 0; i <= 300; i++){
int mid1 = l+(r-l)/3;
int mid2 = r-(r-l)/3;
ans = min(ans,check(mid1));
ans = min(ans,check(mid2));
if(check(mid1) > check(mid2))l = mid1;
else r = mid2;
//如果写l=mid1-1,r=mid2+1,就是14/15,因为r-l=3,l=2,可能一直错过中间点
//在这中间反复横跳,啊举了例子但是忘记了
}
// for (int i = l; i <= r; i++) {
// ans = min(ans,check(i));
// }//顺手再检验一下
cout << ans << endl;
//不理解十足的不理解,让我再学学再来改
//我来了!我懂了!我真的懂了!
return 0;
}
C - Minimization
哦简单题
题解:
n个数字从1到n,每次框取k个数字变成这其中的最小值,要求最后所有数都变成1。
按顺序分组,从包含1的那组开始框取即可。
代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
int k,n;
int a[100005];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
cout << ceil((double)(n-1)/(double)(k-1)) << endl;
return 0;
}
D - Equal Cut
看出来是三分了但是做不出来,加上没时间了就直接过了没写。后来补题的时候还是有点懵,三分变形吧算是。
题解:
给定含n个数字的数组a,切三刀变成三个数组的和分别是p,q,r,s,求最大值与最小值差值的最小值。
先中间切一刀,开始遍历这个中间数,然后左右分别切一刀,希望切下来的俩块使差值尽可能小。然后每个中间数的最小值比较即可。用了一些前缀和思想,方便运算。
代码:
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define int long long
int n;
int a[200008];
int qz[200008];
bool check(int x,int y, int aaa) {
if(abs((x+a[aaa]) - (y-a[aaa])) < abs(x - y)) return true;
else return false;
}//判断是否要加上aaa未知的数字a
signed main() {
cin >> n;
a[0] = 0;
qz[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
qz[i] = qz[i-1] + a[i];
}
int b = 1,e = 3;
//b,e是左右俩刀
int ans = 1e9+5;
for (int i = 2; i <= n-2; i++) {
//i是中点
int p = qz[b];
int q = qz[i] - qz[b];
int r = qz[e] - qz[i];
int s = qz[n] - qz[e];
while (check(p,q,b+1) && b+1 < i) {
b++;
p = qz[b];
q = qz[i] - qz[b];
}//一直加到俩边尽可能接近
while (check(r,s,e+1) && e+1 < n) {
e++;
r = qz[e] - qz[i];
s = qz[n] - qz[e];
}
int test[10];
test[0]=p;test[1]=q;
test[2]=r;test[3]=s;
sort(test,test+4);
ans = min(ans,test[3]-test[0]);
//每次遍历的最小值都要相比
}
cout << ans << endl;
return 0;
}
G - Brutality
字符串简单题,题意比较绕,读懂即可
题解:
给出n个数字代表每一次的伤害值,给出k代表每个键最多可连点数(注意,点了其他的键才算破坏连点,停顿仍然算作连续)给出键值,可跳过不可乱序。
直接暴力。
代码:
#include<iostream>
#include<algorithm>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define int long long
int n,k;
int a[200005];
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for(int i = 0; i < n; i++) {
cin >> a[i];
}
string s;
cin >> s;
int res = 1;
int ans = 0;
for (int i = 1; i < s.length()+1; i++) {
if(s[i] == s[i-1]) {
res++;
}
else {
sort(a+i-res,a+i);
for (int j = i-1; j >= max(i-k,i-res); j--) {
ans += a[j];
}
res = 1;
}
// cout << ans << endl;
}
cout << ans << endl;
return 0;
}