bistuacm 2019年第⑧场新生训练赛题解

比赛链接:
http://citel.bjtu.edu.cn/vjudge/contest/view.action?cid=328#overview
比赛难度:cf 1000~1500

A

知识点:字符串
题意:寻找所有单词中大写字母最多的大写字母数量。
解法:单词按空格隔开,所以可以直接scanf读取,自动按空格分割字符串。

#include<bits/stdc++.h>
using namespace std;

int main(){
    int m=0,n;
    cin>>n;
    char s[11111];
    while(scanf("%s",s)!=-1){
        int i,sum=0;
        for(i=0;s[i]!='\0';i++)sum+=(s[i]>='A'&&s[i]<='Z');
        m=max(m,sum);
    }
    cout<<m;
}

B

知识点:枚举
题意:用尽可能少的问号替代第一个字符串的字符,使其成为第二个字符串的子串(问号可代表任意字符)。
解法:由于n只有1000,因此O(n^2)暴力枚举即可。求出最长公共子串。注意需要记录该子串的位置方便统计问号的位置。

#include<bits/stdc++.h>
using namespace std;

int main(){
    int m,n,i,dy=0,j;
    char a[1111],b[1111];
    cin>>m>>n>>a>>b;
    int ma=0;
    for(i=0;i<n-m+1;i++){
        int sum=0;
        for(j=0;j<m;j++)sum+=a[j]==b[i+j];
        if(sum>ma){
            ma=sum;
            dy=i;
        }
    }
    cout<<m-ma<<endl;
    j=dy;
    for(i=0;i<m;i++)if(a[i]!=b[i+j])cout<<i+1<<" ";
}

C

知识点:区间合并/前缀和
题意:数组中每个数a[i]代表对从第i-1个位置往前a[i]个位置染色。问最终未染色数量
解法:即每次对区间:(i-a[i],i-1)染色(若a[i]>i则是对(0,i-1)染色)。在数组上染色问题可以用前缀和解决:区间(x,y)染色即令s[x]++,s[y+1]–。然后最后求一次前缀和,前缀和结果为0的项即代表没被染色的位置。

#include<bits/stdc++.h>
using namespace std;

int a[1111111];
long long sum[1111111]={0};
int main(){
    int n,i;
    cin>>n;
    for(i=0;i<n;i++)scanf("%d",&a[i]);
    for(i=0;i<n;i++){
        sum[i]--;
        if(a[i]>=i)sum[0]++;
        else sum[i-a[i]]++;
    }
    long long s=0;
    for(i=1;i<n;i++)sum[i]+=sum[i-1];
    int cnt=0;
    for(i=0;i<n;i++)cnt+=!sum[i];
    cout<<cnt;
}

D

知识点:图论/dfs
题意:给定一有根树。每次操作选择一个点,和一个颜色,可对该点以及其子树上所有点染成这个颜色。问所有点染色成指定颜色的最小操作数。
解法:显然只要有相邻边目的颜色不同,就需要进行一次额外染色。因此dfs求最终相邻边不同数字的对数即可。

#include<bits/stdc++.h>
using namespace std;

vector<int>g[111111];
int sum=1;
int a[111111];
int visited[111111]={0};
void dfs(int x){
    visited[x]=1;
    int i;
    for(i=0;i<g[x].size();i++){
        if(!visited[g[x][i]]){
            sum+=a[x]!=a[g[x][i]];
            dfs(g[x][i]);
        }
    }
}
int main(){
    int i,n;
    cin>>n;
    for(i=2;i<=n;i++){
        int x;
        cin>>x;
        g[x].push_back(i);
        g[i].push_back(x);
    }
    for(i=1;i<=n;i++)cin>>a[i];
    dfs(1);
    cout<<sum;
}

E

知识点:贪心/字符串
题意:定义两个字母差的绝对值为两个字母的距离。两个字符串的距离为每个字符的距离之和。给定一字符串和一个数字k,求任意一个字符串,使其到给定字符串的距离为k。
解法:先求出可能的距离最大值max(am的字母选择z,nz的字母选择a的情况)。若k>max显然无解。当k≤max时,从前往后遍历字符串,优先选择最大值的情况来消耗k,当k被消耗得当前不需要最大值的情况改变当前字符。之后所有的字符保持原状即可。

#include<bits/stdc++.h>
using namespace std;

int main(){
    int temp[26];
    int n,k,i;
    cin>>n>>k;
    char a[111111];
    cin>>a;
    for(i=0;i<13;i++)temp[i]=25-i;
    for(i=13;i<26;i++)temp[i]=i;
    int sum=0;
    for(i=0;i<n;i++)sum+=temp[a[i]-'a'];
    if(k>sum)cout<<-1;
    else{
        for(i=0;i<n;i++){
            if(k){
                if(k>=temp[a[i]-'a']){
                    if(a[i]>='n')cout<<'a';
                    else cout<<'z';
                    k-=temp[a[i]-'a'];
                }
                else{
                    if(a[i]>='n')cout<<(char)(a[i]-k);
                    else cout<<(char)(a[i]+k);
                    k=0;
                }
            }
            else cout<<a[i];
        }
    }
}

F

知识点:图论/bfs
题意:对一棵树进行染色,需保证相邻两边的3个点颜色不同。求最少的颜色种类,并输出一种染色方案。
解法:对整棵树进行bfs,需要记录每个点的上一个点是哪个点,从某点v搜索到下一个点时,需要满足该点和点v、点v所有子节点、以及点v上一个点的颜色都不同的前提下,从1开始往上染色。

#include<bits/stdc++.h>
using namespace std;

vector<int>g[200011];
int c[200001]={0};
int visited[200001]={0};
int m=1;
void bfs(){
    int i;
    queue<int>q;
    q.push(1);
    visited[1]=1;
    c[1]=1;
    while(!q.empty()){
        int temp=q.front(),k=1;
        for(i=0;i<g[temp].size();i++){
            if(!visited[g[temp][i]]){
                visited[g[temp][i]]=temp;
                while(k==c[temp]||k==c[visited[temp]])k++;
                c[g[temp][i]]=k;
                m=max(m,k);
                k++;
                q.push(g[temp][i]);
            }
        }
        q.pop();
    }
}
int main(){
    int n,i;
    cin>>n;
    for(i=0;i<n-1;i++){
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    bfs();
    cout<<m<<endl;
    for(i=1;i<=n;i++)cout<<c[i]<<" ";
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值