codefoces 双指针尺取法 Codeforces 985E Pencils and Boxes

本文探讨了如何通过尺取法解决铅笔分盒问题。具体地,给定n支铅笔及其权值,每支铅笔必须放入满足特定条件的盒子中。文章详细介绍了如何利用排序和尺取法来确定是否存在一种合法的分配方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考博客
待读:树状数组做法
每日好文:权值线段树
题意:

给定n,k,d,表示给你n支铅笔,每支有一个权值v。现在让你把n支笔放入一些盒子中(盒子数量可以无穷大),每个盒子中至少有k支笔,而且每个盒子中的笔的max(v)-min(v)不超过d。问你能否找到一个合法的放法,可以输出”YES”,否则输出”NO”。

思路:

因为对权值差有要求,所以先进行排序,排序后能放进一个盒子的笔的权值v一定是连续的。之后记录两个值,一个是can[i],表示第i支笔能否作为某一段的终点,另一个是st[i],表示第i支笔能否作为某一段的起点。如果某支笔能作为某一段的终点,那么下一支笔一定可以当做某一段的起点,最后判断最后一支笔能否作为某一段的终点(即can[n]==1是否成立)。这样可以用尺取法(即two pointers)解决:将某一段的起点定为s,终点定为e,如果①起点所在位置可以作为某一段的起点(即st[s]==1成立);②终点到起点的距离大于等于k(即e-s+1>=k);③这一段的最大值减最小值不超过d(因为从小到大排序,所以最大值减最小值不超过d等价于a[e]-a[s]<=d)这三点成立,那么说明以s为起点,e为终点是可行的,则可以把can[e]赋值为1,把st[e+1]赋值为1。在①满足的情况下,直到③不满足之前,一直把e右移(即尺取法的思想)。

AC:code

#include<bits/stdc++.h>
using namespace std;
int a[612345];
int st[612345],ed[612345];
int main()
{

    int n,k,d;
    cin>>n>>k>>d;
    for(int i=1; i<=n; i++)scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    ed[0] = 1;
    st[1] = 1;
    int e =1;
    for(int s=1; s<=n; s++)
    {
        if(st[s]==1)
        {

            while(e<=n&&a[e]-a[s]<=d)
            {
                if(e-s+1>=k)
                {
                    ed[e] = 1;
                    st[e+1] = 1;
                }
                e++;
            }

        }

    }

if(ed[n]==1)
{
    cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
return 0;
}
### Codeforces Round 725 (Div. 3) 中涉及双指针算法的题目 在Codeforces Round 725 (Div. 3)中,有一道名为 "C. Two Teams" 的题目可以使用双指针的方法来解决。这是一道关于如何将两个团队中的成员配对以满足特定条件的问题。 #### 题目描述 给定两个长度分别为 \( n \) 和 \( m \) 的数组 \( a[] \) 和 \( b[] \),其中 \( a[i] \leq b[j] \) 对于所有的 \( i, j \) 成立。现在要找到一种方式使得尽可能多的人被分配到两支队伍之一,并且每支队伍内部的人都能按照某种顺序排列成不下降序列。输出能够安排的最大人数以及具体的方案。 #### 解决思路 为了高效解决问题并减少时间复杂度,采用双指针策略是一个不错的选择。具体来说: - 使用两个指针分别指向当前正在处理的位置 `i` 和 `j`; - 如果发现 \(a[i]\) 小于等于 \(b[j]\),则说明这两个位置上的人可以加入同一个队列;此时更新答案并将对应的指针向前移动一位; - 否则只移动较大的那个数所在的指针直到再次遇到可匹配的情况为止。 这种方法可以在 O(n+m) 时间内完成计算而不需要额外的空间开销。 ```cpp #include <iostream> using namespace std; int main(){ int T; cin >> T; while(T--){ int n,m; cin>>n>>m; vector<int> A(n); for(auto& x:A){ cin>>x; } sort(A.begin(),A.end()); vector<int> B(m); for(auto& y:B){ cin>>y; } sort(B.begin(),B.end()); int cnt = 0; int p1 = 0,p2 = 0; while(p1<n && p2<m){ if(A[p1]<=B[p2]){ ++cnt; ++p1;++p2; }else{ ++p2; } } cout<<cnt<<"\n"; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值