Educational Codeforces Round 172 (Rated for Div. 2) - Codeforces
Problem - A - Codeforces
数学 排序
显然将数组排序之后每次拿最大值,若恰好拿到\(k\)则答案为\(0\),如果中途拿到\(i\)时总和,大于\(k\),则说明之前要加\(a[i]-(sum-k)\)个
如拿完还是小于\(k\),那么答案就是\(k-sum\)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N];
int n,k;
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
sort(a+1,a+1+n);
int sum=0;
for(int i=n;i>=1;i--)
{
sum+=a[i];
if(sum==k)
{
cout<<"0"<<endl;return ;
}
else if(sum>k)
{
cout<<a[i]-sum+k<<endl;return ;
}
}
cout<<k-sum<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
Problem - B - Codeforces
博弈 贪心
若A拿到了一种颜色的所有弹珠则加两分,没拿全加一分,不拿没分
A要最大化A的得分,B要最小化A的得分,A先手
对于一种颜色来说,它的个数为\(1\)时,AB要优先去拿它,如果\(>1\),那么没有区别,因为一定是A拿一个,B再拿一个防止A得两分
由于是A先手,记个数为一的颜色有\(x\)个,\(>1\)有\(y\)个答案就是\(ceil(x/2)+y\)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef pair<int,int>pii;
int a[N];
int n,k;
void solve()
{
scanf("%d",&n);
int cnt[n+10]={0};
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
cnt[x]++;
}
int x=0,y=0,ans=0;
for(int i=1;i<=n;i++)
{
if(cnt[i])
{
if(cnt[i]==1)x++;
else y++;
}
}
cout<<(x+1)/2*2+y<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
Problem - C - Codeforces
贪心 排序 推公式
题意说给出一串二进制字符串,1是B钓的鱼,0是A钓的鱼
将这个字符串划分为若干个连续段,第\(i\)段中每条鱼的分数为\(i-1\),要求B的得分至少超过A的得分\(k\),求最小划分区域个数
刚拿到题目确实没有思路,感觉无比麻烦,这时候可以尝试从一般情况去推普遍的规律
设\(a_i\)为第\(i\)个区域的起始点的下标,\(s_i\)为从\(i\)到\(n\)内B的个数减去A的个数
那么答案则为
这样发现其实答案就是由若干个后缀和相加而来,有多少个后缀和取决于我们如何划分区域
那么只需要算出所有的(除去\(s_1\))之外的后缀和,将其排序,每次取最大值即可,答案就是取的所有后缀和再加上一
为什么一定是后缀和呢,为什么不能从前往后推呢?
如果计算前缀和,将每个区域的结尾(开头和结尾没有区别)设置为\(a_i\)
那么答案则为
没有消去最后一项,计算会很复杂,做题的时候前缀不行换后缀,顺序不行换倒序(😄)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef pair<int,int>pii;
int a[N];
int n,k;
void solve()
{
scanf("%d%d",&n,&k);
string s ;cin>>s;s=' '+s;
a[n+1]=0;
for(int i=n;i>1;i--)
{
a[i]=a[i+1]+(s[i]=='1'? 1:-1);
}
sort(a+2,a+1+n);//不可以计算第一项
int ind=n,cnt=0;long long sum=0;
while(ind>1)
{
sum+=a[ind];
cnt++;ind--;
if(sum>=k)
{
cout<<cnt+1<<endl;return ;
}
}
cout<<"-1"<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
Problem - D - Codeforces
排序 STL 二分 区间合并
(一定要把样例看完再做题......)
题意:第\(i\)个人喜欢\([l_i,r_i]\)的歌曲,若一个人\(j\)喜欢的歌曲满足\(l_j \leq l_i,r_i \leq r_j\),则称\(j\)为\(i\)的预测者,对\(i\)的所有预测者的区间取交集,
得到的区间内的元素个数减去\(i\)的区间内元素个数,求出每个\(i\)对应的该值,无预测者输出\(0\)
这里可以分别求出所求交集的左端点和右端点,记为\(l[i],r[i]\)
先求\(r\)对原数组根据\(l\)升序排序,但要注意这里不能直接利用\(pair<int,int>\)排序,\(pii\)默认是先根据的一个升序排序,再根据第二个升序排序。
但我们此处的做法是将\(l[i]\)处理完之后将\(r[i]\)加入到一个集合中,这样保证了处理每个\(l[i]\)的时候,集合中的\(r[j]\)对应的\(l[j]\)都小于等于\(l[i]\),然后再二分出最小的 大于等于\(r[i]\)的值,即为所求值。
明确过程之后发现,如果\(l[i]==l[i+1]\),那么必须满足\(r[i]\geq r[i+1]\),右端点大的要先放入集合,这样下面右端点较小的值才可以求出交集,反之会使得两者都无解(可以手动带俩个值模拟一下,假设区间只有\([1,5],[1,3]\),那么\([1,5]\)无预测者,\([1,3]\)预测者为\([1,5]\),要\([1,5]\)排在前才可以求出来)以多个关键值排序的时候要想一想具体的关系
然后同理求出左端点,是根据\(r\)降序,\(l\)升序排序,这里二分有个技巧,本质是求最大的 小于等于\(l[i]\)的值,可以用\(upperbound\)算出最小的大于\(l[i]\)的值,如果求出的迭代器不是\(begin()\),说明还有小于等于它的,直接将迭代器减一即可
最后还有个要注意的点是这样去做的话对于两个完全相同的区间,第一次去处理的时候会算出交集,这里要特判一下,也可以用\(map\)标记一下然后输出答案的时候再特判一下
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef pair<int,int>pii;
int n,k;
struct seg
{
int l,r,ind;
};
void solve()
{
scanf("%d",&n);vector<seg>a(n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);a[i].ind=i;
}
set<int>s;
sort(a.begin(),a.end(),[=](seg a,seg b){return a.l==b.l? a.r>b.r:a.l<b.l;});
vector<int>l(n),r(n);
for(int i=0;i<n;i++)
{
int ll=a[i].l,rr=a[i].r,ind=a[i].ind;
if(s.size())
{
auto it=s.lower_bound(rr);
if(it==s.end())r[ind]=-1;
else if(i<n-1&&ll==a[i+1].l&&rr==a[i+1].r)r[ind]=-1;
else r[ind]=(*it);
}
else r[ind]=-1;
s.insert(rr);
}s.clear();
sort(a.begin(),a.end(),[=](seg a,seg b){return a.r==b.r? a.l<b.l:a.r>b.r;});
for(int i=0;i<n;i++)
{
int ll=a[i].l,rr=a[i].r,ind=a[i].ind;
if(s.size())
{
auto it=s.upper_bound(ll);
if(it==s.begin())l[ind]=-1;
else if(i<n-1&&ll==a[i+1].l&&rr==a[i+1].r)l[ind]=-1;
//else if(it==s.end())l[ind]=-1;
else l[ind]=(*(--it));
}
else l[ind]=-1;
s.insert(ll);
}
sort(a.begin(),a.end(),[=](seg a,seg b){return a.ind<b.ind;});
for(int i=0;i<n;i++)
{
if(r[i]!=-1&&l[i]!=-1)
cout<<r[i]-l[i]-a[i].r+a[i].l<<endl;
else cout<<"0"<<endl;
}
//cout<<endl;
}
int main()
{
int t;cin>>t;
while(t--)solve();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧