训练赛4(小)
导语
小型训练赛,E题没做出来
涉及的知识点
贪心、思维、字符串
题目
A(CodeForces 899A )
题目大意:ACM三人一队,现在有许多两人已抱团和一人未抱团且随意,问能组多少个三人小队
思路:尽量用1人填满2人即可,如果1人还剩就每三人组一队
代码
#include <bits/stdc++.h>
using namespace std;
int n,two,one,res;
int main() {
scanf("%d",&n);
while(n--) {
int t;
scanf("%d",&t);
if(t==1)
one++;
else
two++;
}
if(one>=two)
printf("%d",two+(one-two)/3);
else if(one<two)
printf("%d",one);
return 0;
}
B(CodeForces 918B)
题目大意:给出n个ip以及它们的真名,再给出m个ip以及它们的假名,按照“假名 ip; #真名”的格式输出每个ip的信息
思路:直接建立字符串映射,然后根据录入数据输出
代码
#include <bits/stdc++.h>
using namespace std;
int n,m;
unordered_map<string,string>U;
string name,ip;
int main() {
scanf("%d%d",&n,&m);
while(n--) {
cin >>name>>ip;
ip+=";";
U[ip]=name;
}
while(m--) {
cin >>name>>ip;
cout <<name<<" "<<ip<<" #"<<U[ip]<<endl;
}
return 0;
}
C(CodeForces 898B)
题目大意:给出三个正整数 a a a、 b b b、 n n n,判断方程 x × a + y × b = n x×a+y×b=n x×a+y×b=n是否有非负整数解
思路:用最大公因数的性质缩小数据范围,然后暴力判断 n − x × a n-x×a n−x×a能否整除 b b b即可
代码
#include <bits/stdc++.h>
#include <numeric>
using namespace std;
typedef long long ll;
ll n,a,b;
ll gcd(ll x,ll y) {
ll res=max(x,y);
while(res) {
res=x%y;
x=y;
y=res;
}
return x;
}
int main() {
scanf("%lld%lld%lld",&n,&a,&b);
int t=gcd(a,b);
//消除最大公因数,缩小数据范围,如果不能约,直接无解
if(n%t==0) {
a/=t;
b/=t;
n/=t;
} else {
printf("NO");
return 0;
}
if(n%a==0)
printf("YES\n%lld 0",n/a);
else if(n%b==0)
printf("YES\n0 %lld",n/b);
else {
for(ll i=1; i*a<=n; i++)//暴力判断,O(n),判断减去i个a后的值能否被整除
if((n-i*a)%b==0) {
printf("YES\n%lld %lld",i,(n-i*a)/b);
return 0;
}
printf("NO");
}
return 0;
}
D(CodeForces 893C)
题目大意:给出一些点和连接的边,还有每个点的花销,相邻的点可以视为整体,问如何选择点能使所有整体都被访问并花销最小
思路:并查集+贪心记录整体最小值,然后累和
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,fa[121212],ge[121212],ans;
ll Seek(ll x) {
if(x==fa[x])
return x;
return fa[x]=Seek(fa[x]);
}
void Union(ll x,ll y) {
ll a=Seek(x),b=Seek(y);
if(fa[a]!=fa[b])
fa[a]=fa[b];
ge[fa[b]]=min(ge[a],ge[b]);
}
int main() {
scanf("%lld%lld",&n,&m);
for(ll i=1; i<=n; i++) {
fa[i]=i;
scanf("%lld",&ge[i]);
}
while(m--) {
ll a,b;
scanf("%d%d",&a,&b);
Union(a,b);
}
for(ll i=1; i<=n; i++)
if(Seek(i)==i)
ans+=ge[i];
printf("%lld",ans);
return 0;
}
E(CodeForces 888C)
题目大意:给出一个字符串,找一个最小长度k,使得所有子串存在一个相同的字符x
思路:记录下两个相邻(指顺序)的相同字符的最长距离,取这些距离的最小值
代码
#include <bits/stdc++.h>
using namespace std;
int low[27],maxx[27],minn=INT_MAX,len;
bool num[27];
char ch;
int main() {
for(int i=0; i<26; i++)
low[i]=-1;
while((ch=getchar())!='\n') {
maxx[ch-'a']=max(maxx[ch-'a'],len-low[ch-'a']);//更新两个相邻相同字母的最长距离
low[ch-'a']=len++;//更新上一个字母位置
num[ch-'a']=1;
}
for(int i=0; i<26; i++)
if(num[i])//如果该字符存在
maxx[i]=max(maxx[i],len-low[i]);//更新最长距离,末尾到最后一个字母位置
for(int i=0; i<26; i++)
if(num[i])
minn=min(minn,maxx[i]);//取最小值
printf("%d\n",minn);
return 0;
}
F(CodeForces 883E)
题目大意:首先有一个背景,这是一个游戏,一开始有一个完全隐藏的只有小写字母的字符串:*****,提问者可以询问该字符串是否存在某一个字母,如果存在,则显示出该字母所有位置,如原始字符串为abacaba,被隐藏后为*******,询问a后得aaa*a,现在游戏进行到一部分,某些位置已经知道是哪些字母,给出字符串的长度n和现在已知的字符串,再给出m个字符串,可以保证正确答案就在其中,但不保证每个字符串都是符合规则的正确字符串,现在判断询问哪些字符,现在已知的字符串隐藏的位置必定会减少,输出这些字符的数量
思路:对于现在已知的字符串,如果某个位置已经有字母,代表这个字母在字符串中所有位置都未隐藏对于输入的m个字符串,如果对于已知字符串,某个字母的位置变多了,该字符串不合法,舍去,并且,如果输入的字符串未隐藏位置与已知字符串未隐藏位置相同,但值不一样,也是不合法的,去掉不合法字符串后,判断是否存在所有有效字符串共有的字符,如果有,统计数量即可
代码
#include <bits/stdc++.h>
using namespace std;
bool appear[27],maze[1212][27];
char str[51];
int n,m,ans,cnt[27];
int main() {
scanf("%d\n",&n);
for(int i=0; i<n; i++) {
char ch=getchar();
if(isalpha(ch))
appear[ch-'a']=1;
str[i]=ch;
}
scanf("%d\n",&m);
int re=m;
for(int i=0; i<m; i++) {
char t[51];
bool flag=0,tmp[27]= {0};
scanf("%s",t);
for(int j=0; j<n; j++)
if(t[j]==str[j])//如果相同就继续
continue;
else {
if(isalpha(str[j])||appear[t[j]-'a']) {//如果不同,判断是否为合法串
re--;
flag=1;
break;
}
tmp[t[j]-'a']=1;
}
if(!flag)
for(int i=0; i<27; i++)
if(tmp[i])
cnt[i]++;
getchar();
}
for(int i=0; i<27; i++)
if(cnt[i]==re)
ans++;
printf("%d",ans);
return 0;
}