Educational Codeforces Round 120
2021/12/28 6:07:19
本文主要是介绍Educational Codeforces Round 120,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
两个月没打cf了,好不容易打一次,写个题解(
这场C题因为一个小bug 调了好久 还WA了三发,加上考场以为是cf赛制 心态持续爆炸
好在5min想出D题 并且在结束前2min写出来,最后结果还算满意
A. Construct a Rectangle
2s
Problem
给定三个长为 $ l_1,l_2,l_3(l_1,l_2,l_3\in \mathbb{N}^*) $ 的木棍,要求任选一个拆成两段,且每段长度都是正整数,使得四个木棍可以组成一个矩形。
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
给定 \(p_1,p_2,...p_n\) 和 \(s_1,s_2,...,s_n\) ( \(p\) 是排列, \(s\) 是01串),要求满足条件
- \(q\) 是排列
- \((\forall i)(\forall j)((s_i=1 \and s_j=0)\rightarrow q_i>q_j)\)
的 \(q_1,q_2,...,q_n\) 中, \(\sum_{i=1}^n |p_i-q_i|\) 最小的。
Solution
显然 \(s_i=1\) 的 \(i\) 对应的 \(q_i\) 应为 \(1,2,3,...,x\),而 \(s_i=0\) 的 \(i\) 对应的 \(q_i\) 应为 \(x+1,x+2,x+3,...,n-1,n\)
感性理解一下,原来 \(p_i\) 小的 \(q_i\) 也应该小,嗯就这样。
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
给定 \(a_1,a_2,...,a_n\) 和 \(k\),有两种操作
- \(a_i:=a_i-1\)
- \(a_i:=a_j\)
要求用尽可能少的操作使得 \(\sum_{i=1}^n a_i \leq k\)
Solution
首先,最优策略一定是先对最小的数进行若干次操作1,再对最大的几个数依次进行操作2。
把 \(a\) 从小到大排序,假设我们进行了 \(j\) 次操作2和 \(i\) 次操作1。记 \(sum_i=\sum_{k=1}^i a_k\)。
那么操作结束后的数列应该是: \(a_1-j,a_2~a_{n-k},a_1-j,a_1-j,...,a_1-j\)
由 \(\sum_{i=1}^n a_i \leq k\),
有 \((i+1)(a_1-j)+sum_{n-k}-a_1\leq k\),
所以 \(j\geq \frac{sum_{n-k}-a_1-k}{i+1}+a_1\)
因为我们要求 \(i+j\) 的最小值 故令 \(j=max(\lceil \frac{sum_{n-k}-a_1-k}{i+1}+a_1 \rceil,0)\)
枚举 \(i\) 即可。
(有两点要注意 一是答案初始值应为\(max(sum_n-k,0)\)且\(i\)应从\(1\)枚举到\(n-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
给定一个长为 \(n\) 的01串。你可以选定一个包含恰好 \(k\) 个 \(1\) 的子串,并将它任意排序。求可以得到的不同01串个数。模\(998244353\)。
Solution
不妨假定我们选的子串一定是一个包含 \(k\) 个 \(1\) 的极大子串。将它们预处理出来。
观察可以发现,重复计算的方案数就是两个相邻子串交集的不同排列数,将它们减掉即可。
一个01串的不同排列数是一个组合数,可以 \(O(n^2)\) 预处理。
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; }
这篇关于Educational Codeforces Round 120的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享