[题解]Refact.ai Match 1 (Codeforces Round 985) A~C

A - Set

显然答案是\(\max(\lfloor\frac{r}{k}\rfloor-l+1,0)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,l,r,k;
signed main(){
cin>>t;
while(t--){
cin>>l>>r>>k;
cout<<max(0ll,r/k-l+1)<<"\n";
}
return 0;
}

B - Replacement

我们发现只要\(0\)\(1\)各存在至少\(1\)个,操作就能进行下去。所以\(r_i=1\)的操作可以看做删掉一个\(0\)\(r_i=0\)的操作则可以看做删掉一个\(1\)

这样模拟就可以了,每次操作前如果剩余\(0,1\)的个数存在\(0\)则答案是NO

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s,r;
int main(){
cin>>t;
while(t--){
cin>>n>>s>>r;
int cnt0=0,cnt1=0;
bool f=1;
for(char i:s) (i=='0'?cnt0:cnt1)++;
for(char i:r){
if(!cnt0||!cnt1){
f=0;
break;
}
(i=='0'?cnt1:cnt0)--;
}
cout<<(f?"YES\n":"NO\n");
}
return 0;
}

另一种做法很简单,如果\(s[1,n]\)\(1\)的个数减去\(r[1,n-2]\)\(0\)的个数为\(1\),答案就是YES,否则NO。原理差不多,目的是让执行最后一次操作前,序列中恰好有一个\(0\)和一个\(1\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s,r;
int main(){
cin>>t;
while(t--){
cin>>n>>s>>r;
r.pop_back();
int cnts=0,cntr=0;
for(int i:s) cnts+=(i=='1');
for(int i:r) cntr+=(i=='0');
if(cnts-cntr==1) cout<<"YES\n";
else cout<<"NO\n";
}
return 0;
}

C - New Rating

二分解法

考虑二分答案\(x\),转为判断“是否能让最终得分\(\ge x\)”。

\(f[i]\)表示参加第\(i\)场比赛之后的得分;\(g[i]\)表示\(i\)这场比赛前可能的最小得分,使得最终得分\(\ge x\)\(f\)可以通过模拟求出,\(g\)可以用下面的方法求得:

\[g[i]=\begin{cases} x&i=n\\ g[i+1]-1&i\le n,a[i]\ge g[i+1]\\ g[i+1]+1&i\le n,a[i]<g[i+1] \end{cases}\]

只要存在区间\(l\le r\),使得\(f[l-1]\ge g[r+1]\),则说明我们可以让最终得分\(\ge x\)

时间复杂度\(O(n\log n)\)

点击查看代码
#include<bits/stdc++.h>
#define N 300010
using namespace std;
int t,n,a[N],f[N];
bool check(int x){
int g=x;
for(int i=n;i>=1;i--){
if(f[i-1]>=g) return 1;
if(a[i]>=g) g--;
else g++;
}
return 0;
}
int main(){
cin>>t;
while(t--){
cin>>n;
int cur=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]>cur) cur++;
else if(a[i]<cur) cur--;
f[i]=max(f[i-1],cur);
}
int l=0,r=n;
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
cout<<l<<"\n";
}
}

DP解法

\(f[i][j\in[0,2]]\)来表示考虑前\(i\)个比赛,第\(i\)场的状态是\(j\)的答案。其中\(j=0,1,2\)分别表示在跳过的比赛之前、属于跳过的比赛、在跳过的比赛之后。则

\[f[i][j]=\begin{cases} g(f[i-1][0],a[i])&j=0\\ \max(f[i-1][0],f[i-1][1])&j=1\\ \max(g(f[i-1][1],a[i]),g(f[i-1],a[i]))&j=2 \end{cases}\]

转移可以滚掉第\(1\)维。最终答案就是\(\max(f[n][1],f[n][2])\)

时间复杂度\(O(n)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
#define N 300010
using namespace std;
int t,n,a[N],f[3];
int g(int a,int b){return a+(b>a)-(b<a);}
signed main(){
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
f[0]=0,f[1]=f[2]=INT_MIN;
for(int i=1;i<=n;i++){
f[2]=max(g(f[1],a[i]),g(f[2],a[i]));
f[1]=max(f[1],f[0]);
f[0]=g(f[0],a[i]);
}
cout<<max(f[1],f[2])<<"\n";
}
return 0;
}

D - Cool Graph

posted @   Sinktank  阅读(187)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2025-3-6 6:10:44 TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.
点击右上角即可分享
微信分享提示