Educational Codeforces Round 120
两个月没打cf了,好不容易打一次,写个题解(
这场C题因为一个小bug 调了好久 还WA了三发,加上考场以为是cf赛制 心态持续爆炸
好在5min想出D题 并且在结束前2min写出来,最后结果还算满意
A. Construct a Rectangle
2s
Problem
给定三个长为 的木棍,要求任选一个拆成两段,且每段长度都是正整数,使得四个木棍可以组成一个矩形。
Solution
考虑拆出来的两段是对边还是邻边。若是对边,则要求该木棍长为偶数且另外两个木棍长度相等。若是邻边则要求另外两个木棍长度相加等于该木棍。
Code
#include<iostream>
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x;
}
int main(){
int T=read(),a,b,c;
while(T--){
a=read();b=read();c=read();
if(a==b && c%2==0) puts("YES");
else if(b==c && a%2==0) puts("YES");
else if(c==a && b%2==0) puts("YES");
else if(a==b+c||b==a+c||c==a+b) puts("YES");
else puts("NO");
}
return 0;
}
B. Berland Music
2s
Problem
给定 和 ( 是排列, 是01串),要求满足条件
- 是排列
的 中, 最小的。
Solution
显然 的 对应的 应为 ,而 的 对应的 应为
感性理解一下,原来 小的 也应该小,嗯就这样。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x;
}
const int N=200005;
struct P{
int id,p,q,s;
}x[N];
bool cmp(P a,P b){
if(a.s!=b.s) return a.s<b.s;
return a.p<b.p;
}
bool cmpid(P a,P b){return a.id<b.id;}
int main(){
int T=read(),n;char c;
while(T--){
n=read();
for(int i=1;i<=n;++i) x[i].p=read(),x[i].id=i;
for(int i=1;i<=n;++i) cin>>c,x[i].s=(c-'0');
sort(x+1,x+n+1,cmp);
for(int i=1;i<=n;++i) x[i].q=i;
sort(x+1,x+n+1,cmpid);
for(int i=1;i<=n;++i) printf("%d ",x[i].q);
puts("");
}
return 0;
}
C. Set or Decrease
2s
Problem
给定 和 ,有两种操作
要求用尽可能少的操作使得
Solution
首先,最优策略一定是先对最小的数进行若干次操作1,再对最大的几个数依次进行操作2。
把 从小到大排序,假设我们进行了 次操作2和 次操作1。记 。
那么操作结束后的数列应该是:
由 ,
有 ,
所以
因为我们要求 的最小值 故令
枚举 即可。
(有两点要注意 一是答案初始值应为且应从枚举到,二是更新答案时应该用ans=min(ans,max(0,j)+i)
或ans=min(ans,max(i,i+j))
而不是ans=min(ans,i+j)
或ans=min(ans,max(0,i+j))
Code
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define int long long
using namespace std;
inline int read(){
int x=0;char c=getchar();
while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x;
}
int a[200005],sum[200005];
signed main(){
int T=read(),n,k,ans;
while(T--){
n=read();k=read();
for(int i=1;i<=n;++i) a[i]=read();
sort(a+1,a+n+1);
for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
ans=max(0ll,sum[n]-k);
for(int i=1;i<n;++i) {ans=min(ans,max(i,(long long)ceil(i+a[1]-((double)(k-sum[n-i]+a[1]))/(i+1))) );}
printf("%lld\n",max(ans,0ll));
}
return 0;
}
D. Shuffle
2s
Problem
给定一个长为 的01串。你可以选定一个包含恰好 个 的子串,并将它任意排序。求可以得到的不同01串个数。模。
Solution
不妨假定我们选的子串一定是一个包含 个 的极大子串。将它们预处理出来。
观察可以发现,重复计算的方案数就是两个相邻子串交集的不同排列数,将它们减掉即可。
一个01串的不同排列数是一个组合数,可以 预处理。
Code
#include<iostream>
#include<cstdio>
#define int long long
using namespace std;
int n,k,ans,cnt;
int pos[5050],l[5050],r[5050],c[5050][5050];
const int p=998244353;
string s;
int C(int a,int b){if(b==0) return 1; return c[a][b];}
signed main(){
cin>>n>>k;
cin>>s;
for(int i=0;i<=n;++i) c[i][0]=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=i;++j)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%p;
// while(1){
// cin>>n>>k;
// cout<<C(n,k)<<endl;
// }
for(int i=0;i<n;++i) if(s[i]=='1') pos[++cnt]=i; pos[cnt+1]=n; pos[0]=-1;
if(k>cnt||k==0) {cout<<1;return 0;}
for(int i=k;i<=cnt;++i) l[i-k+1]=pos[i-k]+1,r[i-k+1]=pos[i+1]-1;
// for(int i=1;i<=cnt-k+1;++i) cout<<l[i]<<r[i]<<endl;
for(int i=1;i<=cnt-k+1;++i) ans+=C(r[i]-l[i]+1,k)%p,ans%=p;
for(int i=1;i<=cnt-k;++i) ans-=C(r[i]-l[i+1]+1,k-1)%p,ans%=p,ans+=p,ans%=p;
cout<<ans%p;
return 0;
}
作者:_Veritas
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
2020-12-28 五子棋 Python实现