zoukankan      html  css  js  c++  java
  • CF1437E Make It Increasing

    题意描述:

    洛谷

    给你一个长度为 (n) 的序列 (a), 和一个大小为 (m) 的集合 (b), 其中 (b) 集合中的位置不能改,问你最少要修改多少次使得 序列 (a) 严格递增。,修改后保证 (a) 为整数。 无解输出 (-1).

    数据范围: (n,mleq 5 imes 10^5, a_ileq 10^9)

    solution

    比较好玩的构造题。

    有一个结论:如果 (i,j) ((i<j)) 都不修改, 则需要满足 (a_j-a[i] geq j-i)

    因为你要保证 (i-j) 这一段区间严格单调递增,因此每一项至少要与前一项差 (1), 那么可以推出 (a_j) 至少要和 (a_i)(j-i)(1) 才能符合条件,转化成数学形式即 (a_j - a_igeq j-i)

    有了这个结论我们就很好做了。

    首先,我们先考虑一下无解的情况,如果 (i,jin b, i < j) 且 $a[j]-a[i] < j-i $ ,那么肯定是无解的。

    接下来考虑怎么求最少的修改次数。

    显然 (b) 集合会把序列 (a) 分成 (m+1) 段,我们对每一段求一个最少的修改次数,在相加就是最后的答案。

    我们想让修改次数最少,所以这一段区间中的数尽可能多的不被修改。

    由结论可得如果 (a_i)(a_j) 都不被修改,则要满足 (a_j-a_i geq j-i) ,即: (a_j-j geq a_i-i)

    我们把序列 (a) 中每个元素的价值设为 (a_i-i), 然后对 ((b[i-1],b[i])) 这一段区间求一个最长上升子序列的长度就是最多可以保留的数的个数。

    但由于 (b[i],b[i-1]) 这两个位置不能被修改即必须被选入最长上升子序列中,我们需要对代码魔改一下。

    • 初值只有 (f[b[i-1]] = 1), 这样每个元素都可以由 (f[b[i-1]]) 转移过来,也就等价于 (b[i-1]) 一定会被选上。

    • (b[i]) 被选上也就是最长上升子序列的长度为 (f[b[i]])

    求最长上升子序列用树状数组优化一下即可。

    坑点:树状数组的初值要设为 (-inf)

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int N = 5e5+10;
    const int inf = 1e9+10;
    int n,m,ans,flag,cnt;
    int f[N],a[N],b[N],w[N],tr[N];
    inline int read()
    {
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
        return s * w;
    }
    int lowbit(int x){return x & -x;}
    void cover(int x,int val)//还原树状数组
    {
    	for(; x <= N-5; x += lowbit(x)) tr[x] = val;
    }
    void chenge(int x,int val)
    {
        for(; x <= N-5; x += lowbit(x)) tr[x] = max(tr[x],val);
    }
    int query(int x)
    {
        int res = -inf;
        for(; x; x -= lowbit(x)) res = max(res,tr[x]);
        return res;
    }
    int main()
    {
        n = read(); m = read(); 
        w[0] = -inf; w[n+1] = inf;
        b[++cnt] = w[0]; b[++cnt] = w[n+1];
        for(int i = 1; i <= n; i++) b[++cnt] = w[i] = read() - i;
        sort(b+1,b+cnt+1);
        int num = unique(b+1,b+cnt+1)-b-1;
        for(int i = 0; i <= n+1; i++) w[i] = lower_bound(b+1,b+num+1,w[i])-b;
        for(int i = 1; i <= m; i++)
        {
            b[i] = read();
            if(w[b[i]] < w[b[i-1]]) flag = 1;
        }
        b[0] = 0; b[m+1] = n+1;
        memset(tr,128,sizeof(tr));
        if(flag) printf("%d
    ",-1);
        else
        {
            for(int i = 1; i <= m+1; i++)//对每一段进行处理
            {
                f[b[i-1]] = 1;
                chenge(w[b[i-1]],1);
                for(int j = b[i-1]+1; j <= b[i]; j++)
                {
                    f[j] = query(w[j]) + 1;
                    chenge(w[j],f[j]);
                }
                for(int j = b[i-1]; j <= b[i]; j++) cover(w[j],-inf); 
                ans += b[i] - b[i-1] + 1 - f[b[i]];
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    Java continue break 制作简单聊天室程序,屏蔽不文明语言,显示每句话聊天时间 for(;;) SimpleDateFormat("yyyy-MM-dd hh:mm:ss") equalsIgnoreCase
    Java实现随机出题,10道10以内加减法计算
    Java发出声卡蜂鸣生的方法
    Java程序调用自动关机指令 1分钟内自动关机
    Java如何将十六进制数转换为十进制数的自编程序
    告诉你今年是哪个生肖年的java程序
    更新MySQL数据库( java.sql.SQLException: No value specified for parameter 1) 异常 解决方法
    把网上图片下载到本地的java工具类
    exp ORA-01455: converting column overflows integer datatype
    shell date 格式化
  • 原文地址:https://www.cnblogs.com/genshy/p/14435198.html
Copyright © 2011-2022 走看看