文章目录
题目链接
写在前面
昨天晚上打的这场cf打的跟坨⑩一样,一道简单的B题从头卡到尾,最后几分钟才把他AC出来,导致这把比赛直接寄了······,div4没有算法,全是思维,看来思维还得多练啊!
A- A+B Again?
思路
签到题,直接开循环枚举位数即可
code
void solve(){
int n;cin >> n;
int sum=0;
while(n){
sum+=n%10;
n/=10;
}
cout << sum << endl;
return ;
}
B- Card Game
思路
签到题,考虑出现4、2的情况即可(赛时的思路,其实不用这么麻烦,直接比较大小最后乘以2更快)
code
void solve(){
int a,b,c,d;
cin >> a >> b >> c >> d;
int x=max(c,d);
int y=min(c,d);
int s=min(a,b);
int t=max(a,b);
if(s>x){
cout << 4 << endl;
return ;
}
if(t>x && s==x){
cout << 4 << endl;
return ;
}
if(t>x && s>=y){
cout << 2 << endl;
return ;
}
if(x==t && s==t && s>y){
cout << 4 << endl;
return ;
}
if(x==t && s>y){
cout << 2 << endl;
return ;
}
cout << 0 << endl;
return ;
//直接比较大小
//int ans = 2 * (((a1 > b1) + (a2 > b2) > (a1 < b1) + (a2 < b2)) + ((a1 > b2) + (a2 > b1) > (a1 < b2) + (a2 < b1)));
}
C- Showering
思路
首先对于每个区间来说,没有重复的,那么我们就可以将他们全部进行排序
然后判断下一个区间的开头和上一个区间的末尾的差值是否大于等于洗澡的时间即可
特判整体工作区间的前面和后面的时间段即可
code
void solve(){
int cnt=0;
map<int,int> mp;
int n,s,m;
cin >> n >> s >> m;
for(int i=1;i<=n;++i){
int l,r;
cin >> l >> r;
mp[l]=1,mp[r]=1;
}
int k=-1;
for(auto i : mp){
cnt++;
if(k==-1){
int ans=i.fi;
if(ans>=s){
cout << "yes" << endl;
return ;
}
k=i.fi;
}
else{
if(cnt%2){
int ans=i.fi-k;
if(ans>=s){
cout << "yes" << endl;
return ;
}
}
k=i.fi;
}
}
if(m-k>=s){
cout << "yes" << endl;
return ;
}
cout << "no" << endl;
return ;
}
D- Slavic’s Exam
思路
考点:模拟
遍历字符串s,这时会出现3种情况:(k为字符串t的下标,初始值为0)
- s [ i ] 和 t [ k ] 相同 , k + + s[i]和t[k]相同,k++ s[i]和t[k]相同,k++
- s [ i ] 和 t [ k ] 不相同,且 s [ i ] 不为 ? ,跳过 s[i]和t[k]不相同,且s[i]不为?,跳过 s[i]和t[k]不相同,且s[i]不为?,跳过
- s [ i ] 和 t [ k ] 不相同,且 s [ i ] 为 ? ,将 s [ i ] 变为 t [ k ] , k + + s[i]和t[k]不相同,且s[i]为?,将s[i]变为t[k],k++ s[i]和t[k]不相同,且s[i]为?,将s[i]变为t[k],k++
考虑以上情况即可
void solve(){
string s,t;
cin >> s >> t;
int k=0;
for(int i=0;i<s.size();++i){
if(k==t.size()){
if(s[i]=='?') s[i]='a';
}
else{
if(s[i]=='?' || s[i]==t[k]){
s[i]=t[k];
k++;
}
}
}
if(k!=t.size()) cout << "no" << endl;
else{
cout << "yes" << endl;
cout << s << endl;
}
return ;
}
E- Triple Operations
思路
观察题目,我们很明显想到一个思路:先让最小的数变为0,这样每次执行的操作只有
y
/
3
而没有
x
∗
3
y/3而没有x*3
y/3而没有x∗3
接着我们继续观察,每次都执行
y
/
3
y/3
y/3 ,很明显想到变化的区间在
[
3
i
,
3
i
+
1
−
1
]
[3^i,3^{i+1}-1]
[3i,3i+1−1]时,所执行的操作数是一样的
我们只要判断
[
l
,
r
]
[l,r]
[l,r]是否满足这个区间即可
code
void solve(){
int l,r;
cin >> l >> r;
int n=l,ans=0;
while(n){
n/=3;
ans+=2;//将*3变化的操作数也加上
}
l=l+1;//左区间
int t=1,x=1;
while(l<=r){
int rr=x*3-1;//右区间
if(rr>=l){
ans+=(min(rr,r)-l+1)*t;
l=rr+1;
}
t++;//操作数+1
x*=3;
}
cout << ans << endl;
return ;
}
F- Expected Median
思路
由于最后需要排序,那么0和1的位置都固定好了,我们只需要统计个数即可
我们要满足中位数为1,那么1的个数必然大于0的个数
所以我们可以枚举0的个数,0的范围在
0
−
m
i
n
(
k
/
2
,
z
e
r
o
)
0 - min(k/2,zero)
0−min(k/2,zero)
接着判断当前0的个数加上1的个数是否大于等于k,若满足则1所需的个数为
k
−
i
k-i
k−i
然后套用组合数的模板即可,在0的个数中取
i
i
i个,在1的个数中取
k
−
i
k-i
k−i个
code
const int N=2e5+5;
int fac[N],inf[N];
int qpow(int a, int b){
int res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void init(){ // 预处理,fac[]表示阶乘, inf[]表示阶乘的逆元
fac[0] = inf[0] = 1;
for(int i = 1; i <= N; i++){
fac[i] = fac[i - 1] * i % mod;
inf[i] = inf[i - 1] * qpow(i, mod - 2) % mod;
}
}
int C(int n,int m){
return fac[n] * inf[m] % mod * inf[n - m] % mod;
}
void solve(){
int n,k;
cin >> n >> k;
int a=0,b=0;
for(int i=1;i<=n;++i){
int x;cin >> x;
if(x==0) a++;
else b++;
}
int ans=0;
for(int i=0;i<=min(k/2,a);++i){
if(b+i>=k){
int x=k-i;
int t=C(b,x)%mod*C(a,i)%mod;
ans=(ans+t)%mod;
}
}
cout << ans << endl;
return ;
}
G1- Ruler (easy version)
思路
首先x的范围在
[
2
,
999
]
,
l
o
g
2
999
<
10
[2,999],log_2999<10
[2,999],log2999<10,那么我们就可以用二分进行处理
对于每次询问? a b
我们可以令a等于1,那么
a
∗
b
=
b
a*b=b
a∗b=b,我们只需要判断交互器所给的值是等于b还是等于b+1即可
若交互器所给的值为b,说明所求的值在右边,将左边界往右移
反之,将右边界往左移
最后输出左边界即可
code
int ask(int x,int y){
cout << "? " << x << " " << y << endl;
int res;cin >> res;
return res;
}
void solve(){
int l=2,r=999;
int a,b;
while(l<r){
int x=l+r>>1;
if(ask(1,x)==x+1) r=x;
else l=x+1;
}
cout << "! " << l << endl;
return ;
}