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;
}