But my words, like si|

MessageBoxA

园龄:4年10个月粉丝:4关注:0

2024-09-09 21:41阅读: 13评论: 0推荐: 1

CSP模拟 取模

涉及知识点:反悔贪心

前言

最近开始写 CSP 模拟的题,实际上考的题一点也不 CSP

题意

有一个长度为 n 的序列 A0Ai<k,你可以每次选取一个区间,将区间内所有元素 +1,然后将区间内所有元素对 k 取模。问最少几次操作可以把序列中所有元素都变为 0

思路

假设现在有一个数列 [2,3,1,0,3,2]k=4,我们考虑如何将它变为 0

发现每次操作后都要模 k 的限制非常烦,因此我们做一个转化,每次操作直接加,而“区间内所有元素等于 0” 转化为了 “区间内所有元素modk=0 ”。

以上图为例,最优的方案为 (1,7),(2,6),(3,5),(4,4),(4,4),共五步,我们把表示“增加值”的序列 B 用橙色表示。

如果把整张图“倒过来”,如下图,我们惊喜地发现这是一个经典问题,求多少次区间加 1 能覆盖代表 B 的橙色部分。很显然,操作次数即为 B 的差分数组 Bd 中的 >0 的数之和。

并且我们发现 Bi=(kAi)+ck,且 c 的取值只可能为 01 时才优,为什么?因为考虑初始时差分数组 Bd 中所有元素绝对值一定是 <k 的,那么 Bi 加一次 k 体现在 Bd 上便为 Bid+k,Bi+1dk,可以发现此时 Bid 必为正数且 Bi+1d 必为负数,那么再加由于 Bi+1d 只会越来越负不计入答案,而 Bid 为正且越来越大,Bd 的正数和只会更大。

因此我们考虑找到最优的给 Bik 的方案,根据差分数组的性质,若 B 上有连续的一段区间 [l,r1] 都被加上 k,则反映到 Bd 上为 Bld+k,Brdk,此时 Bld 必为正数,Brd 必为负数,假设原先 Brd 为正数,那么这个操作对答案的贡献为原先的 Brd 减去现在的 Bld。听到这 solution 大概已经浮出水面了:即遍历差分数组 Bd,对于每个大于 0Bid,找它前面最小的 Bjd 判断操作后能不能使得答案变得更小,贪心即可。

注意操作后 Bid 将会变成负数,它也可以和后面的其他 Btd>0 进行一次操作。这有点类似反悔贪心的思想:对于 j<i<tji 操作,i 再和 t 操作实际上等价于 jt 操作,i 就被“反悔”掉了。

代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
const int MAXN=1e7+5;
int n=0,k,a[MAXN],b[MAXN];
string num;
priority_queue<pii,vector<pii>,greater<pii>>pq;
int main(){
    freopen("modulo.in","r",stdin);
    freopen("modulo.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>k>>num;
    a[++n]=num[0]-'0';
    for(int i=1;i<num.size();i++){
        if(num[i]!=num[i-1])
            a[++n]=num[i]-'0';
    }
    for(int i=1;i<=n;i++){
        if(a[i]!=0) a[i]=k-a[i];
    }
    for(int i=1;i<=n;i++){
        b[i]=a[i]-a[i-1];
    }
    for(int i=1;i<=n;i++){
        if(b[i]<0) pq.push(make_pair(b[i],i));
        else if(b[i]>0){
            if(pq.empty()) continue;
            int id=pq.top().second;
            if(b[id]+k<b[i]){
                pq.pop();
                b[id]+=k;
                b[i]-=k;
                pq.push(make_pair(b[i],i));
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        if(b[i]>0) ans+=b[i];
    }
    cout<<ans<<endl;
    return 0;
}

后记

CF有道题有点类似,实际上还要简单一点,CF1852C

本文作者:MessageBoxA

本文链接:https://www.cnblogs.com/SkyNet-PKN/p/18405404

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MessageBoxA  阅读(13)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 evening Corn Wave
  2. 2 Группа крови Кино
  3. 3 The Sound Of Silence Simon & Garfunkel
  4. 4 dB doll YUE.STEVEN
Группа крови - Кино
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.