2024 暑假友谊赛-热身1

A.Wall - AtCoder abc079_d - Virtual Judge

题意有点绕,我是用dfs搜一遍,走过的列自然不能重新走一遍,不然就会浪费。对所有数字用map存一下就不用重复计算了。

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5+100;
const int mod = 998244353;
int n,m,k;
int c[10][10];
map<int,int>v;
int min1=INT_MAX;
bool hang[10],lie[10];

void dfs(int hangxx,int cost){
    if(hangxx==1){
        min1=min(min1,cost);
        return;
    }
    for(int j=0;j<10;j++){
        if(hang[hangxx]&&lie[j]) return;
        lie[j]=1;
        hang[hangxx]=1;
        dfs(j,cost+c[hangxx][j]);
        hang[hangxx]=0;
        //lie[j]=0;
    }
    return;
}

void sovle(){
    int sum=0;
    cin>>n>>m;
    int a[n][m];
    for(int i=0;i<10;i++){
        for(int j=0;j<10;j++){
            cin>>c[i][j];
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            cin>>a[i][j];
            if(a[i][j]!=1&&a[i][j]!=-1){
                v[a[i][j]]++;
            }
        }
    }
    for(auto ed:v){
        dfs(ed.first,0);
        sum+=min1*ed.second;
        min1=INT_MAX;
        memset(hang,sizeof(hang),0);
        memset(lie,sizeof(lie),0);
    }
    cout<<sum<<endl;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1; 
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

B.C - Linear Approximation

长度为n的序列,找任意一个整数b,使abs(a[i]-(i+b))的和最小。
先将a[i]减去i,那么就是求a[i]-b的绝对值和最小.
转换模型我们可以把a[i]看成数轴上的点,那么就是要求数轴上一个点到其他点的距离最小。

假设找的点是蓝色点,向左移动d个单位,则左边点到它的距离-d,右边+d,那么-4d+2d=-2d减少了2d.
可见只要蓝点左右两边点数不同就不是最优解,那么使左右两边点数相同的就是这些点坐标的中位数了。

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5+10;
const int mod = 998244353;
int n,m,k;

void sovle(){
    cin>>n;
    vector<int>a(n);
    for(int i=0;i<n;i++){
        cin>>a[i];
        a[i]-=i+1;
    }
    int sum=0;
    sort(a.begin(),a.end());
    for(int i=0;i<n;i++){
        sum+=abs(a[i]-a[(n)/2]);
    }
    cout<<sum<<endl;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1; 
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

C.C - Minimization

因为这是一个排列,所以最后都会变成1,故从1开始改是最优解,对于k长度的框,让1在1-k每个单位长度开始滑动,每次取min

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5+10;
const int mod = 998244353;
int n,m,k;

void sovle(){
    int ii=0;
    cin>>n>>k;
    vector<int>a(n);
    for(int i=0;i<n;i++){
        cin>>a[i];
        if(a[i]==1){
            ii=i;
        }
    }
    int sum=INT_MAX;
    for(int i=max((ll)0,ii-k+1);i<=ii;i++){
        int u=ii-i,v=k-u-1;
        int num=1;
        num+=(ii-u+k-2)/(k-1);
        num+=(n-ii-v-1+k-2)/(k-1);
        sum=min(sum,num);
    }
    cout<<sum<<endl;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1; 
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

G.Problem - 1107C - Codeforces

找出每个长度大于k的连续子字符串,取出最小的多余的部分的a[i]就是答案

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e5+10;
const int mod = 998244353;
int n,m,k,sum,num;
int x,y,z;
map<pair<int,int>,int>v;
int a[N];

void sovle(){
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    string s;cin>>s;
    for(int i=1;i<n;i++){
        if(s[i]==s[i-1]){
            int begin=i-1,end;
            while(i<n&&s[i]==s[i-1]){
                i++;
            }i--;
            end=i;
            if(end-begin+1>k) v[mk(begin,end)]=1;
        }
    }
    int sum=0,num=0;
    for(auto ed:v){
        sort(a+ed.first.first,a+ed.first.second+1);
        int u=ed.first.second-ed.first.first+1-m;
        for(int i=ed.first.first;i<ed.first.first+u;i++){
            sum+=a[i];
        }
    }
    for(int i=0;i<n;i++){
        num+=a[i];
    }cout<<num-sum<<endl;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1; 
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值