CCF-CSP认证考试准备第九天

先开始刷洛谷的差分算法,再继续开始2022年第2题
[[差分(difference)]]
### Day9: 1.# P2367 语文成绩 2.# P3397 地毯  3.202203-2

#### 1.# P2367 语文成绩(一维差分)
(1)题目就是要给原数组多段区间高效地加上一个常数,即利用差分算法
(2)代码(100):
```
#include <bits/stdc++.h>

using namespace std;

int main(){
    ios::sync_with_stdio(false);
    int n,p;
    cin>>n>>p;
    vector<int> va(n+1,0);
    vector<int> vd(n+1,0);
    for(int i=1;i<=n;i++){
        cin>>va[i];
    }
    for(int i=1;i<=n;i++){
        vd[i]=va[i]-va[i-1];
    }
    int x,y,z;
    while(p--){
        cin>>x>>y>>z;
        vd[x]+=z;
        if(y+1<=n){
            vd[y+1]-=z;
        }
    }
    for(int i=1;i<=n;i++){
        va[i]=va[i-1]+vd[i];
    }
    int min=numeric_limits<int>::max();
    for(int i=1;i<=n;i++){
        if(va[i]<min){
            min=va[i];
        }
    }
    cout<<min;
    return 0;
}
```

#### 2.# P3397 地毯(二维差分)
(1)一开始写越界了,因为二维差分改变子矩阵的值涉及x2+1,y2+1,所以说差分数组D要比原数组行和列都至少大1
(2)代码(100):
```
#include <bits/stdc++.h>

using namespace std;

int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    vector<vector<int>> va(n+1,vector<int>(n+1,0));
    vector<vector<int>> vd(n+2,vector<int>(n+2,0));//注意两个n+2
    int x1,y1,x2,y2;
    while(m--){
        cin>>x1>>y1>>x2>>y2;
        vd[x1][y1]++;
        vd[x1][y2+1]--;
        vd[x2+1][y1]--;
        vd[x2+1][y2+1]++;
    }        
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            va[i][j]=va[i-1][j]+va[i][j-1]-va[i-1][j-1]+vd[i][j];
        }    
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cout<<va[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}
```

#### 3.202203-2:出行计划(差分)
(1)题目不等式写出来了,感觉是用差分和前缀和优化,但是没想出来究竟是哪个数组用前缀和,哪些区间差分加常数。
学习:
由题意可以列出:q+k≤t≤q+k+c−1  
则q的范围是:t+1−k−c≤q≤t−k(因为q是查询,转化为q的范围,然后判断q)
题目给了n组(ti​,ci​),相应的就有n个区间[t+1−k−c,t−k]  
即求对于每个q,要计算落在这n个区间内的哪几个区间中?(**区间判断**)  
**等价于**:
我们可以想象一个数轴,数轴上的每个点处的数是0,**只要被一个区间覆盖,覆盖到的地方就全部+1**,这样处理这n个区间,我们就得到了这n个区间在数轴上的叠加覆盖,数轴上的数是几,那它就在几个区间内。
**即让区间[ti​+1−k−ci​,ti​−k]内的数全部+1呢**(**差分**)
**优化核心**:把原先不等式比较转换为了数组元素查询获取次数
(2)满分代码:
```
#include <bits/stdc++.h>

using namespace std;

const int N=200010;

int main(){
    ios::sync_with_stdio(false);
    int n,m,k;
    cin>>n>>m>>k;
    int t,c;
    vector<int> va(N,0);
    vector<int> vd(N,0);
    for(int i=1;i<=n;i++){
        cin>>t>>c;
        int x=t+1-k-c;
        int y=t-k;
        //题目q的范围引发的边界情况的讨论不能少
        if(y<=0){
            continue;
        }
        //数组的边界
        x=max(1,x);
        //for循环里面只改变差分数组
        vd[x]++;
        vd[y+1]--;
    } 
    //只要构建前缀和数组一次即可
    for(int i=1;i<=N;i++){
        va[i]=va[i-1]+vd[i];
    }
    int q;
    while(m--){
        cin>>q;
        cout<<va[q]<<endl;
    }
    return 0;
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值