加载中...

双指针

遍历每个区间的双指针 最后 while() i=j-1

搭档

给出一群男女的各自的魅力值 只有魅力值之差为小于等于1的时候才会搭档 求出最多可以同时多少对搭档

排序+男女指针,
先将男、女魅力值排序,如果可以搭档,那是最好。若不能,就调魅力值小的那一边向后走

sort(a + 1, a + n + 1);
    sort(b + 1, b + m + 1);
    while (i <= n && j <= m) {
        if(abs(a[i] - b[j]) <= 1) ans ++, i ++, j ++;
        else if(a[i] > b[j]) j ++;//b小 b向右走
        else if(a[i] < b[j]) i ++;
    }

奶牛棒球https://www.acwing.com/problem/content/description/1947/

(X,Y,Z) 需满足,Y 在 X 的右边,Z 在 Y 的右边,并且从 Y 到 Z 的距离在 [XY,2XY] 之间,其中 XY 表示从 X 到 Y 的距离。


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

using namespace std;

const int N = 1010;

int n;
int p[N];

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n; i ++ ) scanf("%d", &p[i]);
    sort(p, p + n);
    
    int res = 0;
    for (int i = 0; i + 2 < n; i ++ )//i+2是因为需要给后面的两个指针留下标位置
        for (int j = i + 1, l = j + 1, r = j + 1; j + 1 < n; j ++ )//i+1是因为需要给后面的一个指针留位置
        {// j-i < k-j < 2*(j-i ) 对于满足区域的k都可以 
            while (l < n && p[l] - p[j] < p[j] - p[i]) l ++ ;//左端点l++是找到最左边的满足条件所以是<
            while (r < n && p[r] - p[j] <= 2 * (p[j] - p[i])) r ++ ;//右端点是找到最右边满足条件所以是>
            res += r - l;//计算下标
        }

    printf("%d\n", res);
    return 0;
}



最长重复子序列

双指针
当发现s[a[i]]>1 减少的是s[a[j]]而不是s[a[i]]

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 1e5+10;
int s[N],a[N];
int n,res;
int main()
{
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> a[i];
    for (int i = 0,j=0; i < n; i ++ ){
        s[a[i]]++;
        while(j<n&&s[a[i]]>1){
            s[a[j]]--;
            j++;
            
        }
        res=max(res,i-j+1);
    }    
    cout << res;
    return 0;
}

数组元素的目标和https://www.acwing.com/video/252/

如果我的 a从小到大 b从大到小枚举 当a+b超过目标值的时候就b就变小 o m+n的复杂度

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int a[N],b[N];
int main()
{
    int n,m,x;cin>>n>>m>>x;
    for (int i = 0; i < n; i ++ ) cin >> a[i];
    for (int i = 0; i < m; i ++ ) cin >> b[i];
    for (int i = 0,j=m-1; i < n; i ++ ){
        while(j>=0&&a[i]+b[j]>x) j--;
        if(a[i]+b[j]==x){
            cout << i<<" "<<j;
            break;
        }
    }
    
    return 0;
}

判断子序列https://www.acwing.com/problem/content/2818/
判断数组a的数 是不是数组b的 子序列
那么就i 和 j 分别从0开始 先让j移动当i

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
    for (int i = 0; i < m; i ++ ) scanf("%d", &b[i]);

    int i = 0, j = 0;
    while (i < n && j < m)//
    {
        if (a[i] == b[j]) i ++ ;
        j ++ ;
    }

    if (i == n) puts("Yes");
    else puts("No");

    return 0;
}


日志统计https://www.acwing.com/problem/content/1240/

int main()
{
    scanf("%d%d%d", &n, &d, &k);
    for (int i = 0; i < n; i ++ ) scanf("%d%d", &logs[i].x, &logs[i].y);
//x是时间点 y是id 以x为时间段
    sort(logs, logs + n);

    for (int i = 0, j = 0; i < n; i ++ )
    {
        int id = logs[i].y;
        cnt[id] ++ ;

        while (logs[i].x - logs[j].x >= d)
        {
            cnt[logs[j].y] -- ;
            j ++ ;//满足条件
        }

        if (cnt[id] >= k) st[id] = true;
    }

    for (int i = 0; i <= 100000; i ++ )
        if (st[i])
            printf("%d\n", i);

    return 0;
}

最长连续子序列https://www.acwing.com/problem/content/4397/

不超过k重复的个数
双指针

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6+10;
int w[N],cnt[N];
int main()
{
    int n,k;
    cin >> n>>k;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
    int res=0,l,r;
    for (int i = 1, j = 1,t = 0 ; i <= n; i ++ ){
        if(cnt[w[i]]==0)  t++;
        cnt[w[i]]++;
        
        while( t>k ){
            if(cnt[w[j]]==1) t--;
            cnt[w[j]]--;
            j++;
        }
        
        
        if(i-j+1>res){
            res=i-j+1;
            l=j,r=i;
            
        }
        
    }
    cout << l<<" "<<r;
    
    
    
    return 0;
}

最大子矩阵

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2005,inf=1e9;
int s1[N],s2[N];
int a[N],b[N];
int main()
{
    int n,m;
    cin >> n>>m;int x;
    for (int i = 1; i <= n; i ++ ){
        scanf("%d", &x);
        s1[i]=s1[i-1]+x;
    }
    for (int i = 1; i <= m; i ++ ){
        scanf("%d", &x);
        s2[i]=s2[i-1]+x;
    }
    for (int len = 1; len <= n; len ++ ){//获取 这个长度的数组的最小值
        a[len]=inf;
        for (int i = 1; i+len-1 <= n; i ++ ){
            int j=i+len-1;
            
            a[len]=min(a[len],s1[j]-s1[i-1]);
            
        }
    }
    
    for (int len = 1; len <= m; len ++ ){
        b[len]=inf;
        for (int i = 1; i+len-1 <= m; i ++ ){
            int j=i+len-1;
            
            b[len]=min(b[len],s2[j]-s2[i-1]);
            
        }
    }
    int res=0;cin>>x;
    
    for (int i=1,j=m;i<=n;i++){//最大
        while(j&& a[i]>x/b[j] ) j--;
         res=max(res,j*i);
            
        
        
    }
    cout << res;
    return 0;
}

天气预报https://ac.nowcoder.com/acm/contest/30532/G
求满足区间里面 0的个数>a&&1的个数>b 连续的区间数个数
因为是连续的 所以左端点固定后 j到达满足的情况后 j及j后面的答案都满足 res++n-j+1;

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
long long  cnt[2];
signed main(){
    int n,a,b;
    cin>>n>>a>>b;
    string s;cin>>s;
    
    s=" "+s;
    long long res=0;
    if(a==0&&b==0) {
        
      res++; 
    }
    for(int i=1,j=0;i<=n;i++){
        int t=0;
        if(s[i]=='0') t=0;
        else t=1;
        while(j<n&&(cnt[0]<a||cnt[1]<b) ){
            j++;
            cnt[s[j]-'0']++;
       }
       if((cnt[0]>=a&&cnt[1]>=b))
        res+=n-j+1;
        
        cnt[s[i]-'0']--;//记得删除
    }        
    
    cout<<res;
    return 0;
}
posted @ 2022-02-08 00:23  liang302  阅读(58)  评论(0编辑  收藏  举报