CF edu144 A-C补题
做完的cf打的一般,因为最近忙于物理实验,很久没有做题。脑子也不怎么灵活,所以这场也是犹豫很久才决定打的。赛时速通两题,然后坐牢的比赛结束。rank 2300+ 还算上了一点分。
题目链接
A. Typical Interview Problem 签到
题意:构造一个字符串s,给你一个字符串t,问你t是否是s的子串。
思路:直接构造s,然后用find函数查询一下即可。注意构造s时多构造几位。(很多大佬都wa了一发)。
void Showball() {
string s="";
for(int i=1;i<=10000;i++){
if(i%3==0) s+="F";
if(i%5==0) s+="B";
}
int n;
cin>>n;
string t;
cin>>t;
if(s.find(t)!=s.npos){
cout<<"YES"<<endl;
}else{
cout<<"NO"<<endl;
}
}
B. Asterisk-Minor Template 构造
题意:定义一种匹配:给定一个只含有小写字母和’*'组成的字符串。
如果可以通过将‘*’变成任何字符串(可以是空串)使得s=t。那么就称s和t是匹配的。(s中的‘*’数量不能超过字母的数量)。
现在给你两个字符串a和b。问你能否构造出一个字符串s,使得s同时和a与b匹配。
思路:我们可以对a和b字符串进行分类讨论。如果a和b开头相同
那么我们构造字符串
a
[
0
]
+
"
∗
"
a[0]+"*"
a[0]+"∗"即可。同理,如果a和b结尾相同。那么可以构造
"
∗
"
+
a
.
b
a
c
k
(
)
"*"+a.back()
"∗"+a.back()。对于剩下的情况。由于开头和结尾都不一样,所以我们需要两个"*",那么我们就需要a和b至少有长度为2的公共子串。由于n很小,那么我们直接暴力枚举一遍即可。
构造成
"
∗
"
+
s
u
b
s
t
r
+
"
∗
"
"*"+substr+"*"
"∗"+substr+"∗"即可。
void Showball() {
string a,b;
cin>>a>>b;
if(a[0]==b[0]) {
cout<<"YES"<<endl;
cout<<a[0]<<"*"<<endl;
return;
}
if(a.back()==b.back()){
cout<<"YES"<<endl;
cout<<"*"<<a.back()<<endl;
return;
}
int ok=0;
string res="";
for(int i=0;i<a.size()-1;i++){
string t=a.substr(i,2);
if(b.find(t)!=b.npos){
ok=1;
res=t;
break;
}
}
if(ok){
cout<<"YES"<<endl;
cout<<"*"<<res<<"*"<<endl;
}
else cout<<"NO"<<endl;
}
C. Maximum Set 思维
题意:给你两个数l和r。要求你去构造一个集合。保证集合中的任何两个元素a和b满足 a整除b或者b整除a。要求求出集合的最大元素数,以及最大元素数的情况下集合的种类数。
思路:首先最大元素数比较好求,就是
l
∗
2
k
≤
r
l*2^k \leq r
l∗2k≤r满足不等式的最大的
k
k
k。即
l
o
g
2
(
r
/
l
)
+
1
log_2(r/l)+1
log2(r/l)+1。
对于集合种类数。我们发现最小的数不一定是
l
l
l,也可以是
l
+
1
,
l
+
2
,
.
.
.
l+1,l+2,...
l+1,l+2,...。最大可以到多少呢?稍微分析一下,可知最大为
r
/
2
k
r/2^k
r/2k。那么一共有
r
/
2
k
−
l
+
1
r/2^k-l+1
r/2k−l+1种情况。除了这种情况,我们发现还可以将其中的连续相乘的一位2换成3。举个例子:
l
∗
2
∗
2
∗
2...
≤
r
l*2*2*2...\leq r
l∗2∗2∗2...≤r。可以换成
l
∗
3
∗
2
∗
2
∗
2....
≤
r
l*3*2*2*2....\leq r
l∗3∗2∗2∗2....≤r,并且最多只能换一个3。因为
3
∗
3
>
2
∗
2
∗
2
3*3>2*2*2
3∗3>2∗2∗2,那么就和最大元素数这个条件相矛盾。那么这种情况的个数就可以类比第一种情况进行求解。
l
,
l
+
1
,
.
.
.
r
/
(
2
k
−
1
∗
3
)
l,l+1,...r/(2^{k-1}*3)
l,l+1,...r/(2k−1∗3),那么一共有
r
/
(
2
k
−
1
∗
3
)
−
l
+
1
r/(2^{k-1}*3)-l+1
r/(2k−1∗3)−l+1。又因为我们有
k
k
k个位置可以换成3。所以最后再乘上3即可。
void Showball() {
int l,r;
cin>>l>>r;
int len = __lg(r/l);
int maxn=1<<len;
int res1=max(0,r/maxn-l+1),res2;
if(maxn>=2) res2=max(0,(r/(maxn*3/2)-l+1))*len;
cout<<len+1<<" "<<res1+res2<<endl;
}