枚举算法
一、枚举
例题
1、连号区间数
题目信息
思路
[a,b]连号区间的性质:区间中的最大值-最小值=b-a;
注:这里的a,b值下标数,因为是连续的,所以每两个数之间的值相差为1,在区间[a,b]中一共有b-a+1个数,若为连号,相差的值为b-a。
题解
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define maxsize 10010
using namespace std;
int n;
int a[maxsize];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int count=0;
int max,min;
for(int i=0;i<n;i++) //枚举区间左端点
{
max=min=a[i];
for(int j=i;j<n;j++) //枚举区间右端点
{
if(a[j]>max) max=a[j];
if(a[j]<min) min=a[j];
if(max-min==j-i) count++;
}
}
cout<<count<<endl;
return 0;
}
2、递增三元组
题目信息
思路
暴力做法
用三个for循环来进行比较,符合条件,count++
但是会超时
优化
枚举B数组,对于Bj,判断:
(1)在A中有多少个小于Bj
(2)在C中有多少个大于Bj
方法一:前缀和
方法二:排序+二分
对A、C进行二分,Bj作为分界值
要考虑边界问题,如果二分后l和r都等于0或都等于n-1,还要进行分类讨论(以都等于0为例):
(1)a[n-1]左边的所有数都小于b[j],a[n-1]大于b[j]
(2)a[n-1]左边的所有数都小于b[j],a[n-1]也小于b[j]
题解
暴力做法
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define maxsize 100010
using namespace std;
int n;
int a[maxsize],b[maxsize],c[maxsize];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int count=0;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i];
for(int i=0;i<n;i++) cin>>c[i];
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
for(int k=0;k<n;k++)
{
if(a[i]<b[j]&&b[j]<c[k]) count++;
}
}
}
cout<<count<<endl;
return 0;
}
优化
方法一:前缀和
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define maxsize 100010
using namespace std;
int n;
int a[maxsize],b[maxsize],c[maxsize];
int acnt[maxsize]; //记录a数组中每个数出现的次数
int ccnt[maxsize]; //记录c数组中每个数出现的次数
int s[maxsize]; //记录每个数出现的次数
int as[maxsize]; //as[i]表示在a数组中小于b[i]的数的个数
int cs[maxsize]; //cs[i]表示在c数组中大于b[i]的数的个数
//前缀和
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i];
a[i]++;
}
for(int i=0;i<n;i++)
{
cin>>b[i];
b[i]++;
}
for(int i=0;i<n;i++)
{
cin>>c[i];
c[i]++;
}
//求as[i]
for(int i=0;i<n;i++) acnt[a[i]]++;
for(int i=1;i<maxsize;i++) s[i]=s[i-1]+acnt[i];
for(int i=0;i<n;i++) as[i]=s[b[i]-1];
//求cs[i]
for(int i=0;i<n;i++) ccnt[c[i]]++;
for(int i=1;i<maxsize;i++) s[i]=s[i-1]+ccnt[i];
for(int i=0;i<n;i++) cs[i]=s[maxsize-1]-s[b[i]];
int count=0;
for(int i=0;i<n;i++) count +=as[i]*cs[i];
cout<<count<<endl;
return 0;
}
方法二:排序+二分
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
#define maxsize 100010
using namespace std;
int n;
int a[maxsize],b[maxsize],c[maxsize];
//排序二分
int bsearch_l(int u)
{
int l=0,r=n-1;
while(l<r)
{
int mid=(l+r)/2;
if(a[mid]>=u) r=mid;
else l=mid+1;
}
return r;
}
int bsearch_r(int u)
{
int l=0,r=n-1;
while(l<r)
{
int mid=(l+r+1)/2;
if(c[mid]<=u) l=mid;
else r=mid-1;
}
return l;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
int count=0;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i];
for(int i=0;i<n;i++) cin>>c[i];
sort(a,a+n);
sort(c,c+n);
int num1,num2;
for(int i=0;i<n;i++)
{
if(a[n-1]<b[i]){
num1=n;
}else{
num1=bsearch_l(b[i]);
}
if(c[0]>b[i])
{
num2=n;
}else{
num2=bsearch_r(b[i]);
num2=n-1-num2;
}
count +=num1*num2;
}
cout<<count<<endl;
return 0;
}
上述代码中sort的用法可以参考以下文章:
C++ sort()排序详解
3、特别数的和
题目信息
思路
把所有数字都枚举一遍,判断其中是否包含2、0、1、9,如果包含,sum加上这个数
题解
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
int sum=0;
cin>>n;
for(int i=1;i<=n;i++)
{
int tmp=i;
while(tmp>0)
{
int num=tmp%10;
if(num==2||num==0||num==1||num==9)
{
sum +=i;
break;
}
tmp /=10;
}
}
cout<<sum<<endl;
return 0;
}
补充:如果给出一个字符形式的如“2019”,如何转化成整数?
string str="2019";
int x=0;
for(int i=0;i<str.size();i++)
{
x=x*10+str[i]-'0';
}