2024 暑假友谊赛-热身1

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;
}

  • 17
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值