2024.12.2 Educational Codeforces Round 172
Solved: 4/6
Upsolved: 5/6
Rank: 205
脑洞题做多了导致套路题不会做了。。。
A. Greedy Monocarp
题意:给一个序列,每次可以给其中一个数加1,问最少操作多少次可以满足当从大到小取数时取到的数之和会恰好等于
从大到小排序,设恰好小于
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() void solve(){ int n,k; cin>>n>>k; vector<int> a(n); ll sum=0,ans=-1; for(int& x:a)cin>>x,sum+=x; sort(all(a)); for(int i=0;i<n;++i){ if(sum<=k){ans=k-sum;break;} sum-=a[i]; } cout<<ans<<'\n'; } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
B. Game with Colored Marbles
题意:有一个序列,两人轮流取数。先手每取到一个值都会得 1 分,如果取到某个值的所有数又会额外得 1 分。先手希望得分最多,后手希望得分最少。问最优策略下的分数。
最优策略下,一定是先取完所有出现次数为 1 的数(先手会取得
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() void solve(){ int n,x; cin>>n; vector<int> c(n+1); for(int i=0;i<n;++i)cin>>x,++c[x]; int cnt1=0,cnt2=0; for(int i=1;i<=n;++i){ if(c[i]==1)++cnt1; else if(c[i]>1)++cnt2; } cout<<cnt1+(cnt1&1)+cnt2<<'\n'; } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
C. Competitive Fishing
题意:有一个
每个权值增加的位置对答案的贡献是从这个位置开始的后缀和。因此给所有后缀和排序,从大到小加直到超过
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define all(x) (x).begin(),(x).end() void solve(){ int n,k; cin>>n>>k; string a; cin>>a; vector<int> s(n); for(int i=n-1;i;--i)s[i-1]=s[i]+(a[i]=='1'?1:-1); s.pop_back(); sort(all(s)); int m=1,sum=0; for(int i=n-2;~i;--i){ if(sum>=k)break; sum+=s[i],++m; } if(sum<k)cout<<"-1\n"; else cout<<m<<'\n'; } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
upd: 被叉了。叉点:2e5 个 0。死因:sum 爆 int
D. Recommendations
题意:有
对所有区间按左端点从小到大排序,用set维护右端点,枚举到一个区间时其右端点的lower_bound就是覆盖区间交的右端点。反过来做一遍即可得到区间交的左端点。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pii; #define all(x) (x).begin(),(x).end() struct node{int l,r,id;}; void solve(){ int n; cin>>n; vector<node> a(n); for(int i=0;i<n;++i)cin>>a[i].l>>a[i].r,a[i].id=i; sort(all(a),[=](node a,node b){return a.l<b.l||a.l==b.l&&a.r>b.r;}); set<int> s; vector<int> l(n),r(n); for(int i=0;i<n;++i){ auto it=s.lower_bound(a[i].r); if(it==s.end())r[a[i].id]=-1; else r[a[i].id]=*it; if(i<n-1&&a[i].l==a[i+1].l&&a[i].r==a[i+1].r)r[a[i].id]=-1; s.insert(a[i].r); } s.clear(); sort(all(a),[=](node a,node b){return a.r>b.r||a.r==b.r&&a.l<b.l;}); for(int i=0;i<n;++i){ auto it=s.upper_bound(a[i].l); if(it==s.begin())l[a[i].id]=-1; else l[a[i].id]=*(--it); if(i<n-1&&a[i].l==a[i+1].l&&a[i].r==a[i+1].r)l[a[i].id]=-1; s.insert(a[i].l); } sort(all(a),[=](node a,node b){return a.id<b.id;}); for(int i=0;i<n;++i){ if(l[i]==-1||r[i]==-1)cout<<"0\n"; else cout<<(r[i]-l[i])-(a[i].r-a[i].l)<<'\n'; } } int main(){ ios::sync_with_stdio(0);cin.tie(0); int T; cin>>T; while(T--)solve(); }
E. Vertex Pairs
题意:给一棵
首先可以注意到:因为集合的大小至少为
以重心为根(如果有两个重心要分别做一遍)。从大到小枚举节点看是否可以删除。因为答案集合一定包含重心,所以要删除一个点只能删除以它为根的整棵子树。
考虑如何快速判断能否删除。dfs序将子树转化为区间,然后用树状数组维护每个位置的值是否能被删除:
-
每个值的两个点的lca一定不能被删除;
-
若一个值的两个点有一个点被删了,那么另一个点不能再被删。
删除过程中维护树状数组,判断时判区间和大于0即可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!