尺取法(双指针)

ACM常用的解题技巧:尺取法

POJ 3320 (尺取法)

 



一道例题

算法一:尺取法O(N)

#include <iostream>
#include <cstring>
#include <algorithm>

#define debug1(var) \
    cout << #var << " = " << var << endl 
#define debug(var1, var2) \
    cout << #var1 << " = " << var1 << " " << #var2 << " = " << var2 << endl  
    
using namespace std;

typedef long long LL;

const int N = 1e6 + 10;

int n, a, b;
LL zero[N], one[N];
LL res;
char s[N];

bool check(int l, int r)
{
    if(r < l)   return false;//多一步判断
    if(zero[r] - zero[l - 1] >= a
        && one[r] - one[l - 1] >= b)
        return true;
    return false;
}

int main()
{
    cin >> n >> a >> b;
    cin >> s + 1;
    for(int i = 1; i <= n; i ++ )
    {
        zero[i] = zero[i - 1] + (s[i] == '0');
        one[i] = one[i - 1] + (s[i] == '1');
    }
    
    int st = 1, en = 1;
    for(int i = 1; i <= n; i ++ )
    {
        while(en <= n && !check(st, en))   en ++;
        if(en > n)  break;
        res += (n - en + 1);
        // debug(st, en);
        // debug1(res);
        st ++ ;
    }
    if(a == 0 && b == 0)    res ++ ;
    cout << res << endl;
    return 0;
}

算法二:二分(O(NlogN))

#include <iostream>
#include <cstring>
#include <algorithm>

#define debug1(var) \
    cout << #var << " = " << var << endl 
#define debug(var1, var2) \
    cout << #var1 << " = " << var1 << " " << #var2 << " = " << var2 << endl  
    
using namespace std;

typedef long long LL;

const int N = 1e6 + 10;

int n, a, b;
LL zero[N], one[N];
LL res;
char s[N];

bool check(int l, int r)
{
    if(r < l)   return false;
    if(zero[r] - zero[l - 1] >= a
        && one[r] - one[l - 1] >= b)
        return true;
    return false;
}

int main()
{
    cin >> n >> a >> b;
    cin >> s + 1;
    for(int i = 1; i <= n; i ++ )
    {
        zero[i] = zero[i - 1] + (s[i] == '0');
        one[i] = one[i - 1] + (s[i] == '1');
    }
    int st = 1, en = 1;
    for(int i = 1; i <= n; i ++ )
    {
        while(en <= n && !check(st, en))   en ++;
        if(en > n)  break;
        res += (n - en + 1);
        // debug(st, en);
        // debug1(res);
        st ++ ;
    }
    if(a == 0 && b == 0)    res ++ ;
    cout << res << endl;
    return 0;
}



4394. 最长连续子序列 - AcWing题库

注意本体判重不能用set,会超时,因为在set里面查找元素是线性的,而数组只需要O(1)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_set>

using namespace std;

const int N = 500010, M = 1000010;

int l, r, n, k;
int resl, resr, d;
int a[N], cnt[M], sum;

int main()
{
    //输入输出优化
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    cin >> n >> k;
    for(int i = 1; i <= n; i ++ )   cin >> a[i];

    for(l = 1; l <= n; l ++ )
    {
        if(l > 1 && (-- cnt[a[l - 1]] == 0))    sum -- ;
        while(r != n)
        {
            r ++ ;
            if(cnt[a[r]])   cnt[a[r]] ++ ;//如果这个数加入过了
            else if(sum < k && !cnt[a[r]])//第一次加入,并且有空间
            {
                cnt[a[r]] ++ ;
                sum ++ ;
            }
            else 
            {
                r -- ;
                break;
            }
        }
        if(r - l + 1 > d)
        {
            d = r - l + 1;
            resl = l;
            resr = r;
        }
    }
    
    cout << resl << " " << resr << endl;
    
    return 0;
}

441s是关闭缓冲区后的,1857s是没有输入输出优化的。

可见在输入很大的时候,输入输出优化的效果还是很好的。



posted @ 2022-05-05 08:41  光風霽月  阅读(19)  评论(0编辑  收藏  举报