您的位置:首页 > 其它

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

2019-05-24 20:56 183 查看

比赛链接:
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]<<" ";
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: