zoukankan      html  css  js  c++  java
  • CF1278C-Berry Jam-(前缀和)

    https://vjudge.net/problem/CodeForces-1278C

    题意:有2n瓶果酱,中间有一个楼梯隔开,从中间往左或右两边清空果酱,使得两种果酱的数量相等,最少要清空多少瓶

    思路:第一眼看到并没有什么思路,想用果酱数量的前缀和,但不知道怎么运用,看到一篇博客,把数字2改为-1这几个字眼,恍然大悟。


     例如第一组数据

    原数据 1,1,1,2,2,         1,2,1,2,1,1,2

    变为   1,1,1,-1,-1,1,   -1,1,-1,1,1,-1

    前缀和 1,2,3,2,1,2,     0,1,0,1,0,-1

    因为清除果酱只能从中间的楼梯向两边扩展,所以左边的前缀和是→累加的,右边的前缀和是←累加的也叫后缀和吧。正负分别表示某种果酱多出的数量,相加相等则表示数量相等。如上的红色字体位置,二者之间的果酱都需要清除掉,共6瓶。为了使清除的果酱数量尽可能少,相同的前后缀和,左边前缀和尽量往右靠,右边后缀和尽量往左靠。

    又如另一组数据

    原数据 1,0,0,      1,0,0

    变为   1,-1,-1,    1,-1,-1

    前缀和 1,0,-1,    -1,-2,-1

    显然去掉左边2瓶就是答案。

    选择红色位置用aid数组和bid数组,这两个数组起到指示下标的作用。

    第三组数据的应对方法详看代码。

    第四种数组1,2,  1,1或者1,1,  2,1之类的,需要对0做出处理。在这个数据上wa很多次。详看代码。

    import java.util.Arrays;
    import java.util.Scanner;
    
    public class Main {
    
        public static void main(String[] args) {
            Scanner scan=new Scanner(System.in);
            int n,x;
            
            int  t=scan.nextInt();
            while(t!=0) {
                int p=100000;
                int [] a=new int[100005];//左边果酱前缀和 →
                int [] b=new int[100005];//右边果酱后缀和 ←
                int [] aid=new int[200005];
                int [] bid=new int[200005];
                //前缀和的数字下标,aid[2]=5表示a前缀数组内容为2的在前缀和数组下标为5的位置
                t--;
                n=scan.nextInt();
                aid[p]=0;
                for(int i=1;i<=n;i++) {//从左到右输入,直接计算前缀和
                    x=scan.nextInt();
                    if(x==1)
                        a[i]=a[i-1]+1;
                    else 
                        a[i]=a[i-1]-1;
                    
                    int idx=a[i]+p;//防止遇到负数导致数组越界
                    aid[ idx ]=i;//前缀和尽量往右靠,i越来越大
                }
                
                for(int i=1;i<=n;i++) {//从左到右输入
                    x=scan.nextInt();
                    if(x!=1)
                        x=-1;
                    b[i]=x;
                }
                bid[p]=n+1;
                for(int i=n;i>=1;i--) {//从右往左计算后缀和
                    b[i]+=b[i+1];
                    
                    int idx=b[i]+p;
                    bid[idx]=i;//后缀和尽量往左靠,i越来越小
                }
    
                int ans=2*n;//最多把全部果酱拿走,应付第3组数据
                for(int i=-n;i<=n;i++) {
                    if( (aid[p+i]!=0 && bid[p-i]!=0) || (i==0)) 
                        ans=Math.min(ans,n-aid[p+i]+bid[p-i]-1);
                }
                System.out.println(ans);
            }
        }
    
    }
  • 相关阅读:
    js内置数据类型
    vue禁止复制的方式
    阻止element组件中的<el-input/>的粘贴功能
    Vue插件集合
    qs.parse()、qs.stringify()、JSON.stringify() 用法及区别
    es6数组的一些函数方法使用
    文章段落首字母缩进两个字符
    深圳scala-meetup-20180902(3)- Using heterogeneous Monads in for-comprehension with Monad Transformer
    深圳scala-meetup-20180902(2)- Future vs Task and ReaderMonad依赖注入
    深圳scala-meetup-20180902(1)- Monadic 编程风格
  • 原文地址:https://www.cnblogs.com/shoulinniao/p/12075697.html
Copyright © 2011-2022 走看看