SMU_ACM 3.4.2024-3.10.2024

本文介绍了如何在编程中使用二进制枚举法处理多个只有两种状态的变量,通过位运算快速列举所有可能情况,并以示例展示了其在求解实际问题中的应用,如优化温度需求和计算区间异或等。同时提及了前缀和、差分数组和矩形枚举等技术的扩展和使用场景。
摘要由CSDN通过智能技术生成

二进制枚举

核心:左移枚举所有情况+按位与判断情况存不存在

在有多个变量,每个变量仅有 用与不用 两种情况时,用此方法来列出所有情况

@离散数学

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

离线做法

适用于数据量不大但运算较多时,在程序中将各种情况处理出来存在数组中,在输出时直接查找。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值