二进制枚举
核心:左移枚举所有情况+按位与判断情况存不存在
在有多个变量,每个变量仅有 用与不用 两种情况时,用此方法来列出所有情况
@离散数学
有m个变量于是有2的m次方种情况,用位运算的方式表示即为:1<<m;
例题:通过二进制枚举获得所有情况然后判断每种情况能不能满足温度需求,并不断找出最小花费。
#include<bits/stdc++.h>
using namespace std;
int res=1e9;
int main(){
int N,M;
cin>>N>>M;
vector<array<int,3>> dan(N);
vector<array<int,4>> nuan(M);
for(auto &[x,y,m]:dan) cin>>x>>y>>m;
for(auto &[l,r,k,p]:nuan) cin>>l>>r>>k>>p;
for(int s=0,t=1ll<<M;s<t;s++){ \\二进制枚举
vector<int> sumnuan(101);
int sum=0;
for(int i=0;i<M;i++){
if(!(s&(1<<i))) continue;
auto [l,r,k,p]=nuan[i];
sum+=p;
for(int j=l;j<=r;j++) sumnuan[j]+=k;
}
int flag=1;
for(auto [x,y,m]:dan){
int g=1e9;
for(int i=x;i<=y;i++){
g=min(sumnuan[i],g);
if(g>=m) continue;
flag=0;
break;
}
}
if(flag) res=min(res,sum);
}
cout<<res;
return 0;
}
前缀和思想的扩展
例题:这题有两个坑,第一个是题中给出的式子可简化为 a^b 第二个是要开一个数组储存异或和 不然也会TLE
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<int> arr(n+1),xo(n+1);
for(int i=1;i<=n;i++){
cin>>arr[i];
}
for(int i=1;i<=n;i++){
xo[i]=xo[i-1]^arr[i]; \\存储异或和
}
int m;
cin>>m;
while(m--){
int l,r;
cin>>l>>r;
cout<<(xo[r]^xo[l-1])<<endl;
}
return 0;
}
差分数组
例题:一个有序段中的极差等于按序两两数之差的和。所以,一个n个数的有序数组,分成m段,要使每段的极差和最小,只需将按序两两数之差排序,然后取前n-m个数的和,也是贪心思想。
#include<bits/stdc++.h>
using namespace std;
int main(){
int m,n;
cin>>n>>m;
vector<int> dai(n),cha(n);
for(auto &a:dai) cin>>a;
for(int i=1;i<n;i++){
cha[i]=dai[i]-dai[i-1];
}
sort(cha.begin(),cha.end());
int sum=0;
for(int i=1;i<=n-m;i++){
sum+=cha[i]; //cout<<cha[i];
}
cout<<sum;
return 0;
}
矩形的枚举
例题:设出ax,ay,bx,by,四层for暴力枚举
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<pair<int,int>> po(n);
for(auto &[x,y]:po) cin>>x>>y;
set<vector<int>> se;
se.insert(vector<int>());
for(int ax=0;ax<=50;ax++)
for(int bx=0;bx<=50;bx++)
for(int ay=0;ay<=50;ay++)
for(int by=0;by<=50;by++){
vector<int> s;
for(int k=0;k<n;k++){
if(po[k].first>=ax && po[k].first<=bx && po[k].second>=ay && po[k].second<=by) s.push_back(k);
}se.insert(s);
}\\矩形的枚举
cout<<se.size();
return 0;
}
杂项
auto相关
vector<int> v(n);
vector<array<int,3>> vv(n);
\\cin
for(auto &x:v) cin>>x;
for(auto &[a,b,c]:vv) cin>>a>>b>>c;
\\read
for(auto [x,y,z]:vv){
x==vv[I][0],y==vv[i][1],z==vv[i][2];
}
输入大型数组时
#include<bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
const int inf = 1e9;
离线做法
适用于数据量不大但运算较多时,在程序中将各种情况处理出来存在数组中,在输出时直接查找。