Educational Codeforces Round 171 (Rated for Div. 2) 10.28 ABCD题解
Educational Codeforces Round 171 (Rated for Div. 2) 10.28 (ABCD)题解
A. Perpendicular Segments
数学(math)计算几何(geometry)题意:
给定一个
如果有多个输出,输出任意一个即可。
输入:
第一行一个整数
每组一行三个整数
输入附加限制:输入的
输出:
每组数据两行,第一行四个整数表示
第二行四个整数表示
样例输入:
4
1 1 1
3 4 1
4 3 3
3 4 4
样例输出:
0 0 1 0
0 0 0 1
2 4 2 2
0 1 1 1
0 0 1 3
1 2 4 1
0 1 3 4
0 3 3 0
样例解释:
在第一个样例中,四个点可以如下:
在第二个样例中,四个点可以如下:
在第三个样例中,四个点可以如下:
在第四个样例中,四个点可以如下:
分析:
由于题目给定的输出限制是保证一定有解,那么我们逆向思维,考虑什么限制条件他是无解的。
对于一个矩阵,如果他是正方形对角线一定垂直。这是合理的,那如果是长方形呢?
假设输入的
那么我们考虑与
我们证明,可以得到
我们可以得到
我们发现,欲求解出最长的
带入
由于
那么我们可以有贪心得到:每次都取最大正方形的对角线作为
所以我们输出
ac 代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
int a[N];
int t,n;
int x,y,k;
signed main() {
cin>>t;
while(t--){
cin>>x>>y>>k;
int A_x,A_y,B_x,B_y,C_x,C_y,D_x,D_y;
int m=min(x,y);
A_x=0,A_y=0;
B_x=m,B_y=m;
C_x=0,C_y=m;
D_x=m,D_y=0;
cout<<A_x<<" "<<A_y<<" "<<B_x<<" "<<B_y<<endl;
cout<<C_x<<" "<<C_y<<" "<<D_x<<" "<<D_y<<endl;
}
return 0;
}
B. Black Cells
二分(binary search) 暴力枚举(brute force)题意:
有一个长方形格子,从左到右编号为
给定长度为
每次可以选取数组中的两个元素,
数组
我们需要求解出符合题意
输入:
第一行一个整数
每组第一行一个整数
接下来一行
输出:
每组一行一个整数
样例输入:
4
2
1 2
1
7
3
2 4 9
5
1 5 8 10 13
样例输出:
1
1
2
3
样例解释:
在第一个样例中,使用
在第二个样例中,使用
在第三个样例中,使用
在第四个样例中,使用
分析:
我们发现这个题目,就是需要求出比较合适数对之间最小值,它允许一个元素单独涂。
那么我们很容易发现,当数组长度
如果
因为假设他是偶数位,他前面一定有奇数个元素,再因为两两配对涂色,就一定会导致存在一个单独的元素,前后矛盾了,所以他只能在奇数位单独涂。
基于上面的分析,我们可以采用暴力枚举来完成。
先判断
如果是奇数,枚举奇数位单独的情况,再里面枚举两个元素差值的最大值,最后所有这样的单独位得到的结果取最小值。
我们再讲一下另一个思路,由于我们发现结果一定有:
所以我们考虑二分。枚举这两个端点,二分的条件就是判断这个
我们来思考一下这个二分
应该如何写?
首先我们的大前提是所有中元素涂色,并且,最多只能有一个其他元素进行涂色。
所以我们每次的时候枚举数组,两个元素直接求差值,如果他比 小,就说明这个数对满足条件,再往后枚举。
相反如果不符合,那么直接就将这个元素单独涂色,再往后枚举。
如果上述操作后,有多个元素需要单独处理,就说明我们的比预期的要小,就更新二分的点。
ac 代码:
//暴力枚举
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2020;
int a[N];
int t,n;
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>t;
while(t--){
int n;
cin>>n;
for (int i=0;i<n;i++)cin>>a[i];
int ans=0;
if(n%2==0) {
for (int i=0;i<n;i+=2){
ans=max(ans,a[i+1]-a[i]);
}
}
else{
ans=0x3f3f3f3f3f3f3f3f;
for (int i=0;i<n;i+=2) {
int res=0;
for (int j=0;j<n;j+=2) {
if (j==i){
j--;
continue;
}
res=max(res,a[j+1]-a[j]);
}
ans=min(ans,res);
}
}
if(ans)cout<<ans<<endl;
else cout<<1<<endl;
}
return 0;
}
//二分
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2010;
int a[N],b[N];
int t,n;
bool check(int mid){
int fl=0;
for(int i=0;i<n;i++){
if(i+1<n&&a[i+1]-a[i]<=mid)i += 1;
else fl++;
}
return fl<=1;
}
signed main() {
cin>>t;
while(t--){
cin>>n;
vector<int>B(n);
for(int i=0;i<n;i++)cin>>a[i];
int l=1;
int r=max(l,a[n-1]-a[0]);
int ans=r;
while(l<=r){
int mid=l+r>>1;
if(check(mid)) {
ans=mid;
r=mid-1;
}
else l=mid+1;
}
cout<<ans<<endl;
}
return 0;
}
C. Action Figures
贪心(greedy) 数据结构(data structures)题意:
即第
但是
需要求解出
输入:
第一行一个整数
每组第一行一个整数
接下来一行一个长度为
输入限制,保证
样例输入:
4
1
1
6
101101
7
1110001
5
11111
样例输出:
1
8
18
6
样例解释:
在第一个样例中,
在第一个样例中,
然后可以在第
最后可以在第
在第一个样例中,
之后他在第
分析:
我们发现,如果存在对应
如何证明?
假设第
天字符串中对应的为 ,即 不去商店购买东西,则第 个玩具只能放在后面的时间购买。
又因为后面的价格高于,那么后面贵的元素优先考虑打折,所以,不论如何操作, 对应的玩具一定会被购买。
那么也就是对应的是可能购买,我们不妨给他存起来。
然后我们再细化考虑其中细节。
我们已经分析了
如果
由于这个玩具就不需要购买了, 就可以移除掉。
我们可以用队列来实现上述操作。
最后实现完之后考虑队列中元素,我们由于可以免费,所以我们只需要对半向上取整再考虑后半部分较小的元素即可。
ac 代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
void solve()
{
int n;
string s;
cin>>n;
cin>>s;
s=' '+s;
int ans=0;
int fg=0;
queue<int> q;
for(int i=s.size()-1;i>=1;i--)
{
if(s[i]=='0')
{
if(q.size()) q.pop();
ans+=i;
}
else
{
q.push(i);
}
}
int sz=(q.size()/2);
int tot=0;
int bk=0;
while(q.size())
{
tot+=q.front();
if(sz)
{
sz--;
bk+=q.front();
}
q.pop();
}
tot-=bk;
cout<<ans+tot<<endl;
}
signed main()
{
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int tt=1;
cin >> tt;
while(tt--) solve();
}
D. Sums of Segments
数学(math)二分(binary search)题意:
给定一个长度为
设定
再构造一个长度为
例如:
之后会有
输入:
第一行一个整数
第二行
第三行一个整数
接下来
样例输入:
4
1 2 5 10
15
1 1
1 2
1 3
1 4
1 5
1 10
5 10
6 10
2 8
3 4
3 10
3 8
5 6
5 5
1 8
样例输出:
1
4
12
30
32
86
56
54
60
26
82
57
9
2
61
分析:
我们发现这是一个数组构造的题目。那么我们来找规律。
我们单纯考虑样例。
索引 | 1 | 2 | 3 | 4 |
---|---|---|---|---|
a | 1 | 2 | 5 | 10 |
那么我们也列出表格
a | 1 | 2 | 5 | 10 |
---|---|---|---|---|
b | 1 | 3 | 8 | 18 |
2 | 7 | 17 | ||
5 | 15 | |||
10 |
我们可以立马发现,在第二行中,每个元素都减去了
那么我们再更新一下这个表格,补全前面空余的部分。
a | 1 | 2 | 5 | 10 |
---|---|---|---|---|
b | 1 | 3 | 8 | 18 |
-4 | 2 | 7 | 17 | |
-4 | -6 | 5 | 15 | |
-4 | -6 | -10 | 10 |
这前面的负数,表示第一行的和加上这几个负值,就可以得到这一行的和。
怎么求?
我们定义的这个负值,是表示这一行减去了多少个。
所以
例如:第一行和是
那么这里就可以迅速得到:
前两行的和就是
前三行的和就是
我们发现每一行减去的都是
我们又发现快速求前几行,他每次都是减去的
对于我们每次对标的第一行,不难发现,他其实是
这样操作,我们取前k行结果就是
对于这个样例,当前的值如下:
a | 1 | 2 | 5 | 10 |
---|---|---|---|---|
1 | 3 | 8 | 18 | |
1 | 4 | 12 | 30 | |
-4 | -6 | -10 | ||
-4 | -10 | -20 | ||
-4 | -14 | -34 |
那么我们取前k行的操作就结束了。
我们再考虑如果他是第二行的第一个元素咋办?
我们只需要取
但是我们可以加呀,我们后面的元素可以快速找出来,有
同理我们也可以搜索第二行第二个数,这样就需要重复减去
接下来我们回到问题本身,给出询问,找到
那么我们可以看成第
我们根据上面的思路,先搜索他在
如何搜?
我们通过公式发现,他是一个的一个序列,我们前 层的元素有多少个?
个,用这个条件来二分即可。
我们搜到的结果是向下取整的(如果正好是整的,就不需要后面的操作了),然后再按照上面思路加上第k+1层前面的这些元素就可以了。
ac 代码:
//建议大家按照上面的思路自己写一下,我这个代码可读性很差。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=300010;
int a[N],s[N],ss[N];
int b[N],bb[N];
int t,n,q;
bool check(int k,int x){
int tmp=(2*n-k+1)*k/2;
if(tmp>x)return false;
else return true;
}
signed main() {
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)s[i]=a[i]+s[i-1];
for(int i=1;i<=n;i++)ss[i]=s[i]+ss[i-1];
for(int i=1;i<n;i++){
b[i]=a[i]*(n-i+1);
}
for(int i=1;i<n;i++)b[i]+=b[i-1];
for(int i=1;i<n;i++)bb[i]=b[i]+bb[i-1];
cin>>q;
while(q--){
int l,r;
cin>>l>>r;
l-=1;
int k_l=0,k_r=n;
int L=0,R=0;
while(k_l<k_r){
int mid=k_r+k_l+1>>1;
if(check(mid,l)){
k_l=mid;
}
else{
k_r=mid-1;
}
}
L+=ss[n]*k_l-bb[k_l-1];
int tmp=l-(2*n-k_l+1)*k_l/2;
int k=k_l+tmp;
if(tmp)L+=ss[k]-b[k_l]+s[k_l]*(n-k);
k_l=0,k_r=n;
while(k_l<k_r){
int mid=k_r+k_l+1>>1;
if(check(mid,r)){
k_l=mid;
}
else{
k_r=mid-1;
}
}
R+=ss[n]*k_l-bb[k_l-1];
tmp=r-(2*n-k_l+1)*k_l/2;
k=k_l+tmp;
if(tmp)R+=ss[k]-b[k_l]+s[k_l]*(n-k);
int ans=R-L;
cout<<ans<<endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧