C++算法之枚举、模拟与排序

博客围绕AcWing上的多道算法题展开,涵盖连号区间数、递增三元组、特别数的和等题目。对每道题给出分析思路,如连号区间数判断Max - Min == j - i,递增三元组用排序 + 二分或前缀和求解等,还给出了相应的代码实现。

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

1.AcWing 1210.连号区间数
分析思路

由题意是在 1∼N 的某个排列中有多少个连号区间,所以每个数出现并且不重复!

如果是连续的,那么Max-Min==j-i([i,j])

代码实现
#include<iostream>
#include<algorithm>
using namespace std;
const int N=10010,INF = 100000000;
int a[N];
int main()
{
    int n;
    cin>>n;
    int count=0;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++)//枚举区间的左端点
    {
        int Max=-INF,Min=INF;
        for(int j=i;j<n;j++)//枚举区间的右端点
        {
           Max=max(Max,a[j]);
           Min=min(Min,a[j]);
           if(Max-Min==j-i) count++;
        }
        
    }
    cout<<count<<endl;
    return 0;
}
2.AcWing 1236.递增三元组
分析思路

由题意可知,需要从A、B、C数组中各取一个,使得A<B<C,所以我们来枚举B数组(由于时间复杂度的限制只能枚举一个数组),这样A,C是独立的互不影响的,只与B数组的大小有关,然后从A中找到小于B的个数、从C中找到大于B的个数,两者相乘。

排序+二分:先对A、C数组进行排序然后用二分求出A中小于B的第一个个数的位置和C中大于B的第一个位置。
前缀和:

代码实现

排序+二分:

#include<iostream>
#include<algorithm>

using namespace std;
const int N=100010;
typedef long long LL;
int a[N],b[N],c[N];

int main()
{
    int n;
    cin>>n;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &c[i]);
    
    sort(a+1,a+n+1);
    sort(c+1,c+n+1);
    
    LL res=0;
    for(int i=1;i<=n;i++)
    {
        int l=1,r=n;
        while(l<r)
        {
            int mid=(l+r+1)/2;
            if(a[mid]<b[i]) l=mid;
            else r=mid-1;
        }
        if (a[l] < b[i]) 
        {
            int temp=l;
            l=1,r=n;
            while(l<r)
            {
                int mid=(l+r)/2;
                if(c[mid]>b[i]) r=mid;
                else l=mid+1;
            }
            if(c[r]>b[i]) res+=(LL)(temp)*(LL)(n-l+1);
        }
        
    }
    cout<<res<<endl;
    return 0;
}

前缀和:

3个数组的所有数都加1,是因为在不影响数与数之间的大小关系下,让该行代码s[b[i] - 1];

避免出现b[i]为0的情况导致空指针异常

#include<iostream>
#include<algorithm>

using namespace std;
const int N=100010;
typedef long long LL;
int a[N],b[N],c[N],s[N],t[N],x[N],y[N];

int main()
{
    int n;
    cin>>n;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]),a[i]++;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &b[i]),b[i]++;
    for (int i = 1; i <= n; i ++ ) scanf("%d", &c[i]),c[i]++;
    
    LL res=0;
    for(int i=1;i<=n;i++)
    {
        s[a[i]]++;
        t[c[i]]++;
    }
    for(int i=1;i<=N;i++)
    {
        x[i]=x[i-1]+s[i];
        y[i]=y[i-1]+t[i];
    }
    for(int i=1;i<=n;i++)
    {
        res+=(LL)(x[b[i]-1])*(LL)(y[N]-y[b[i]]);
    }
    
    cout<<res<<endl;
    return 0;
}
3.
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值