前缀和与差分——练习(一维+二维)

一、前言

        前缀和与差分算是很常用的算法,熟记是有必要的。

                                                        ——题目来源y总每日一题,感觉正适合模板分块讲解系列。

二、浅谈

         我们可以用a数组作为前缀和数组,b数组作为差分数组,因为二者互为逆运算。

        他们常常用做优化,当然也有其他用处。

        先说前缀和,它是很好记的,因为无论一维二维,计算都与它自身相关;再说差分,它相对来说别扭,因为无论一维二维,它往往需要将原始给定数组利用插入函数依次插入到差分数组中去。

        最好用的办法还是自己先画个图,还是容易想起来的。

三、练习

        1.重新排序

        直接记录次数(用差分)。对于排序前:按次数从大到小乘以对应数组元素;对于排序后:按次数从大到小同时从大到小乘以给定数组元素直到次数为0。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+5;

int kn[N],a[N],b[N];
vector<int> v;

void insert(int l,int r,int c){
    b[l]+=c;
    b[r+1]-=c;
}

signed main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>kn[i];
        a[i]=kn[i]+a[i-1];
    }
    int q;
    cin>>q;
    int l,r;
    while(q--){
        cin>>l>>r;
        insert(l,r,1);
    }
    int temp=0,ini=0;;
    for(int i=1;i<=n;i++){
        temp=temp+b[i];
        v.push_back(temp);
        if(temp!=0)ini+=temp*kn[i];
    }
    //cout<<ini<<" ";
    sort(v.begin(),v.end(),greater<int>());
    sort(kn+1,kn+1+n,greater<int>());
    int las=0,k=0;
    for(auto x:v){
        //cout<<x<<" "<<kn[++k]<<endl;
        if(x!=0)las+=x*kn[++k];
    }
    //cout<<las;
    cout<<las-ini;
    return 0;
}

         2.棋盘

        仍然差分记录次数,偶数0白,奇数1黑 

#include<bits/stdc++.h>
using namespace std;
#define int long long

const int N=2010;

int n,m;
int b[N][N],ans[N][N];

void insert(int x1,int y1,int x2,int y2,int c){
    b[x1][y1]+=c;
    b[x1][y2+1]-=c;
    b[x2+1][y1]-=c;
    b[x2+1][y2+1]+=c;
}

signed main(){
    cin>>n>>m;
    
    int x1,y1,x2,y2;
    while(m--){
        cin>>x1>>y1>>x2>>y2;
        insert(x1,y1,x2,y2,1);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            ans[i][j]=ans[i-1][j]+ans[i][j-1]-ans[i-1][j-1]+b[i][j];
            if(ans[i][j]%2==0)cout<<0;
            else cout<<1;
        }
        puts("");
    }
    return 0;
}
  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值