KickStart Round A 2021

K-Goodness String

链接:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068cca3
题意:修改一个字符串里的字符,使得它进行回文对比时刚好相差为K,至少修改多少字符。
题解:直接进行对比,求出相异的格子数为M,则答案为abs(k-M)

#include<bits/stdc++.h>
using namespace std;
int T,len,k;
char s[210000];
int main(){
    cin>>T;
    for(int t=1;t<=T;t++){
        cout<<"Case #"<<t<<": ";
        cin>>len>>k;
        cin>>(s+1);
        int sum=0;
        for(int i=1;i<=len/2;i++){
            if(s[i]!=s[len-i+1])sum++;
        }
        cout<<abs(k-sum)<<endl;
    }
}

L Shaped Plots

链接:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068c509
题意:给一个01矩阵,求有多少个L形状,要求为长边为短边的刚好两倍。
题解:统计每一个格子从四个方向延伸过来它总共有几个,
暴力枚举中间点,计算有多少L可以经过这个。

#include<bits/stdc++.h>
using namespace std;
const int N=1100;
int T,n,m;
int a[N][N],top[N][N],le[N][N],ri[N][N],bo[N][N],ans;
int cal(int x,int y){
    if(x<2||y<2)return 0;
    y=min(x/2,y);
    return y-1;
}
int main(){
    cin>>T;
    for(int t=1;t<=T;t++){
        cout<<"Case #"<<t<<": ";
        cin>>n>>m;
        for(int i=0;i<=n+1;i++){
            for(int j=0;j<=m+1;j++){
                a[i][j]=0;
                top[i][j]=0;
                le[i][j]=0;
                ri[i][j]=0;
                bo[i][j]=0;
            }
        }
        
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>a[i][j];
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==1)top[i][j]=top[i-1][j]+1;
                else top[i][j]=0;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==1)le[i][j]=le[i][j-1]+1;
                else le[i][j]=0;
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=m;j>=1;j--){
                if(a[i][j]==1)ri[i][j]=ri[i][j+1]+1;
                else ri[i][j]=0;
            }
        }
        for(int i=n;i>=1;i--){
            for(int j=1;j<=m;j++){
                if(a[i][j]==1)bo[i][j]=bo[i+1][j]+1;
                else bo[i][j]=0;
            }
        }
        ans=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(a[i][j]==1){
                    ans+=cal(top[i][j],le[i][j]);
                    ans+=cal(top[i][j],ri[i][j]);
                    ans+=cal(le[i][j],top[i][j]);
                    ans+=cal(le[i][j],bo[i][j]);
                    ans+=cal(bo[i][j],le[i][j]);
                    ans+=cal(bo[i][j],ri[i][j]);
                    ans+=cal(ri[i][j],top[i][j]);
                    ans+=cal(ri[i][j],bo[i][j]);
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

Rabbit House

链接:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068cb14
题意:一个矩阵,每个格子有相应高度,可以填高每个格子的高度,要使得相邻格子的高度差最多为1,问至少填多少高度。
题解:贪心算法,每次选最高的,然后检查四周,把不满足的填到高度-1,不断重复这个过程。可以用优先队列来做,每次选最高的即可。复杂度RClog(RC)。
继续优化,可以发现最高的高度为G,则其它所有格子高度至少为G-R-C+2,故可以把选最高的这个过程的优先队列继续优化,用桶来实现,每次选最高的,然后修改其它的,加入桶里的其它位置,直接一遍扫下来即可,复杂度R
C。

#include<bits/stdc++.h>
using namespace std;
const int N=310;
struct node{
    long long x,y,h;
    bool operator <(const node &x)const{
        return h<x.h;
    }
};
long long a[N][N],flag[N][N],ans;
long long T,n,m,x,y;
long long dx[4]={-1,0,0,1};
long long dy[4]={0,-1,1,0};
priority_queue<node>q;
int main(){
    cin>>T;
    for(int t=1;t<=T;t++){
        cout<<"Case #"<<t<<": ";
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                flag[i][j]=0;
                cin>>a[i][j];
                q.push((node){i,j,a[i][j]});
            }
        }
        ans=0;
        while(q.size()){
            node now=q.top();
            q.pop();
            if(flag[now.x][now.y]==1)continue;
            flag[now.x][now.y]=1;
            x=now.x;
            y=now.y;
            for(int i=0;i<4;i++){
                int xx=x+dx[i];
                int yy=y+dy[i];
                if(xx<1||xx>n||yy<1||yy>m)continue;
                if(flag[xx][yy]==1)continue;
                if(now.h-1>a[xx][yy]){
                    ans+=now.h-a[xx][yy]-1;
                    a[xx][yy]=now.h-1;
                    q.push((node){xx,yy,a[xx][yy]});
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

Checksum

链接:https://codingcompetitions.withgoogle.com/kickstart/round/0000000000436140/000000000068c2c3
题意:一个N*N的01矩阵A[i][j],事先求出每行每列的异或值,现在中间有些格子被破坏了,还原这些格子需要B[i][j]的时间,在信息足够的情况下,格子可以直接通过异或值推理出来,问要想还原整个01矩阵,至少需要多少时间。
题解:建立行和列的二分图(上下两排),第i行第j列如果被破坏还原需要B[i][j]的代价,则上排第i个点向下排第j个点连一条边权为B[i][j]的边,除非图变成一棵树或者森林,那么之后就可以通过自我推理推出所有点,否则信息就不够无法还原,目标是砍掉尽可能少的边权和,使剩下的变成一个树或者森林,反过来也就是希望剩下的树的边权最大,则问题变成求最大生成树,总和减去最大生成树权值即是答案。

#include<bits/stdc++.h>
using namespace std;
const int N=510;
int a[N][N],b[N][N];
int T,n,ans,yes,x;
struct arr{
    int x,y,v;
}e[260000];
int cmp(arr a,arr b){
    return a.v>b.v;
}
int fa[N*2];
int getfa(int x){
    if(fa[x]==x)return x;
    return fa[x]=getfa(fa[x]);
}
int main(){
    cin>>T;
    for(int t=1;t<=T;t++){
        cout<<"Case #"<<t<<": ";
        cin>>n;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cin>>a[i][j];
            }
        }
        int sum=0;
        int m=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                cin>>x;
                if(x==0)continue;
                m++;
                e[m].x=i;
                e[m].y=n+j;
                e[m].v=x;
                sum+=x;
            }
        }
        for(int i=1;i<=n;i++)cin>>x;
        for(int i=1;i<=n;i++)cin>>x;
        for(int i=1;i<=n*2;i++)fa[i]=i;
        sort(e+1,e+m+1,cmp);
        int maxsum=0;
        for(int i=1;i<=m;i++){
            int fa1=getfa(e[i].x);
            int fa2=getfa(e[i].y);
            if(fa1!=fa2){
                fa[fa2]=fa1;
                maxsum+=e[i].v;
            }
        }
        cout<<sum-maxsum<<endl;
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值