• 前缀和与差分之IncDec sequence


    参考链接:https://blog.csdn.net/hzk_cpp/article/details/80407014

    题目链接:https://www.acwing.com/problem/content/102/

    前缀和:

    就是一个数组,要快速静态查询区间和,我们只要处理一个数组时A[i]=a[1]+a[2]+...+a[i].

    A[1]=a[1]

    A[2]=a[1]+a[2]

    A[3]=a[1]+a[2]+a[3]

    A[4]=a[1]+a[2]+a[3]+a[4]

    ......

    例如:求[2,4]的区间和,A[4]-A[1]=a[2]+a[3]+a[4]=a[1]+a[2]+a[3]+a[4]-(a[1])

    那么查询区间[l,r]的时候只要输出A[r]-A[l-1].

    那么这是时候预处理是O(n)的,查询一次是O(1).

    在很多情况下这种算法都是可行的,但是必须满足区间减法的性质.

    代码预处理如下:

    for (int i=1;i<=n;i++)
    A[i]=A[i-1]+a[i];
    差分:

    只不过它可以配套前缀和使用.

    差分是一种很巧妙的思想,它的主要用途是维护一个区间的快速修改(加减),但查询是单次的时候.O(n+m)

    这种思想的主体就是维护一个数组A,其中A[i]=原数组a[i]-a[i-1].

    那么就是刚好与前缀和有点像.

    也是互逆的运算.

    那么这怎么快速维护呢?

    也就是说给区间[l,r]+num.

    那么就是给开头A[l]+num,再给结尾A[r+1]-num.

    很好理解啊.

    那么实现如下:

    void add(int l,int r,int num){
    A[l]+=num;A[r+1]-=num;
    }
    那么最后需要查询了,就这样处理一下:

    for (int i=1;i<=n;i++)
    a[i]=a[i-1]+A[i];
    那么就是原来的数组了.

    时间复杂度O(1)修改,O(n)查询.

    差分就是将数列中的每一项分别与前一项数做差,例如:

    一个序列1 2 5 4 7 3,差分后得到1 1 3 -1 3 -4 -3

    这里注意得到的差分序列第一个数和原来的第一个数一样(相当于第一个数减0)

    差分序列最后比原序列多一个数(相当于0减最后一个数)

    性质:

    1、差分序列求前缀和可得原序列

    2、将原序列区间[L,R]中的元素全部+1,可以转化操作为差分序列L处+1,R+1处-1

    3、按照性质2得到,每次修改原序列一个区间+1,那么每次差分序列修改处增加的和减少的相同

    public class Main {
        //前缀和
        public static void fun(int arr[],int A[]){
            /*
            A[1]=a[1]
    
            A[2]=a[1]+a[2]
    
            A[3]=a[1]+a[2]+a[3]
    
            A[4]=a[1]+a[2]+a[3]+a[4]
            */
            for (int i=1;i<arr.length;i++)
                A[i]=A[i-1]+arr[i];
            
        }
        public static int query(int l,int r,int A[]){
            //查询区间[l,r]的时候只要输出A[r]-A[l-1]
            return A[r]-A[l-1];
        }
        //差分
        public static void fun2(int arr[],int A[]){
            for (int i=1;i<arr.length;i++)
                A[i]=arr[i]-arr[i-1];
        }
        public static void add(int l,int r,int num,int A[],int arr[]){
            A[l]+=num;A[r+1]-=num;
            for (int i=1;i<A.length;i++)
                arr[i]=arr[i-1]+A[i];
        }
        
        public static void main(String[] args) {
            int arr[]={0,1,2,3,4};
            int A[]=new int[5];
    //        fun(arr, A);
    //        System.out.println(query(1, 3, A));
    //        System.out.println(query(2, 4, A));
            
            fun2(arr, A);
            add(1, 3, 9, A, arr);
            for (int i = 1; i < arr.length; i++) {
                System.out.println(arr[i]);
            }
        }
    
    }

    IncDec sequence 题解

     对于一个给定的数列arr,它的差分数列A定义为, A[1]=arr[1],A[i]=arr[i]−arr[i−1](2<=i<=n) 即:A[1]=arr[1],A[i]=arr[i]−arr[i−1](2<=i<=n)

    性质,把序列arr的区间[L,R]加d,也就是把arr[l],arr[l+1]........arr[r]都加上d,其实就是它的差分序列B中,A[l]+d,A[r+1]−d其他的位置统统不改变。
    因此在这道题目中,我们就可以利用这个性质,因为我们只要求arr序列中所有的数相同,而不在意这些方案具体是什么,所以说我们就可以转化题目,也就是将对arr序列的+1,−1+1,−1操作,让arr序列相同,改成目标把A2,…,An变成全0即可(因为A[1]=arr[1],所以是A2~A[n]变成0),也就是arr序列全部相等。而且最后得到的arr序列,就是这n个A1
    因为我们有上面所说的性质,那么我们就可以,每一次选取Ai和Aj,2<=i,j<=n而且这两个数,一个为正数,一个为负数,至于为什么要是正负配对,因为我们是要这个A序列2~n都要为0,所以这样负数增加,正数减少,就可以最快地到达目标为0的状态。
    至于那些无法配对的数Ak可以选A1,进行修改。即Ak+d,A1-k,A1不影响全局操作
    所以说我们这道题目得出的答案就是,最少操作数 min(p,q)+abs(p−q),然后最终序列a可能会有abs(p−q)+1种情况。p为b序列中正数之和,而q为b序列中负数之和

    package 差分与前缀和;
    
    import java.util.Scanner;
    
    public class Main1 {
        public static void fun2(long arr[],long A[]){
            for (int i=1;i<arr.length;i++)
                A[i]=arr[i]-arr[i-1];
        }
        public static void main(String[] args) {
            Scanner sc=new Scanner(System.in);
            int n=sc.nextInt();
            long arr[]=new long[n+1];
            for (int i = 1; i < arr.length; i++) {
                arr[i]=sc.nextLong();
            }
            long A[]=new long[n+1];
            fun2(arr, A);
            long positiveNumber=0;
            long negativeNumber=0;
            for (int i = 2; i < A.length; i++) {
                if (A[i]>=0) {
                    positiveNumber+=A[i];
                }else{
                    negativeNumber-=A[i];
                }
            }
            System.out.println(Math.abs(positiveNumber-negativeNumber)+Math.min(negativeNumber, positiveNumber));
            System.out.println(Math.abs(positiveNumber-negativeNumber)+1);
        }
    
    }
    加油啦!加油鸭,冲鸭!!!
  • 相关阅读:
    pythonGUI-wxpython
    [转]谈谈 Mifare Classic 破解
    python-optparse模块给脚本增加参数选项
    [笔记]python
    mac伪装工具macchanger
    mitmproxy
    yersinia的DHCP池耗尽断网攻击
    kalilinux工具中文在线
    MSF内网渗透 扫描模块
    渗透测试的一些总结
  • 原文地址:https://www.cnblogs.com/clarencezzh/p/10315145.html
Copyright © 2020-2023  润新知