SW练习_pro剪刀2_参数探索

这是第一次做答案探索类型的题目

package com.company.real;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
//按照何pro的思路,二分进行答案搜索
//因为答案是线性的,a满足的话,a-1肯定满足
//二分进行探索,找到a满足,a+1不满足的数字,答案就是a
public class JianDao2fen {
    static int N;//格子的数量
    static int K;//剪的次数,0 ~ N-1
    static int[] arrN;
    static int[] tree_max;//最大值
    static int[] tree_min;//最小值
    static int findex=0;
    public static void main(String[] args) throws Exception{
        //System.setIn(new FileInputStream("C:\\\\Users\\\\XAGDC\\\\Desktop\\\\sw\\\\PRO\\\\2Pro 剪子 Scissors\\sample_input.txt"));
        System.setIn(new FileInputStream("C:\\Users\\XAGDC\\Desktop\\sw\\PRO\\2Pro 剪子 Scissors\\eval_input.txt"));
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st=new StringTokenizer(reader.readLine());
        int T=Integer.parseInt(st.nextToken());
        for (int zz = 0; zz <T ; zz++) {
            long startTime=System.currentTimeMillis();
            st=new StringTokenizer(reader.readLine());
            N=Integer.parseInt(st.nextToken());//格子的数量
            K=Integer.parseInt(st.nextToken());//剪的次数,0 ~ N-1*/
            arrN=new int[N];
            st=new StringTokenizer(reader.readLine());
            for (int i = 0; i <N ; i++) {
                arrN[i]=Integer.parseInt(st.nextToken());
            }
            long endTime=System.currentTimeMillis();
            if(N==1){
                System.out.printf("#%d %d \n",(zz+1),0);
                continue;
            }
            if(N==2 && K==1){
                System.out.printf("#%d %d \n",(zz+1),0);//长度是2,切了一次,分数是0
                continue;
            }
            initTree();
            int max=pro(arrN,K);
            endTime=System.currentTimeMillis();
            System.out.printf("#%d %d \n",(zz+1),max);
        }
    }
    public static int pro(int[] arr,int c){
        int min=Integer.MAX_VALUE;
        int max=Integer.MIN_VALUE;
        for (int i = 0; i <arr.length ; i++) {
            if(arr[i]<min){
                min=arr[i];
            }
            if(arr[i]>max){
                max=arr[i];
            }
        }
        int high=max;
        int low=0;
        while(low<=high){
            int mid=(low+high)/2;
            boolean re=checkCon(arr,c,mid);
           // System.out.printf("check c:%d v:%d  result=> %b\n",c,mid,re);
            if(re){//当前数字正确
                boolean re2=checkCon(arr,c,mid+1);
                if(!re2){//当前数字+1不正确
                    return mid+1;
                }
                low=mid+1;
            }else{//当前数字不正确
                /*boolean re2=checkCon(arr,c,mid-1);//当前数字-1正确
                if(re2){
                    return mid-1;
                }*/
                high=mid-1;
            }
        }
        //System.out.printf("process c:%d =%d \n",c,low);
        return low;
    }
    public static boolean checkCon(int[] arr,int count,int v){//按照价值v,切c次  可以切,返回true
        //按照价值v,切c次,可以切,就增加v
        //v增加,会导致count减少
        int start=1;
        int sv=0;
        for (int i = 1; i <=N ; i++) {
                sv=soRan(findex+start,findex+i);
                //System.out.printf("start:%d end:%d =>sv:%d \n",(findex+start+1),(findex+end+1),sv);
                if(sv>v){
                    //System.out.printf("start:%d end:%d \n",(findex+start+1),(findex+i+1));
                    if(count<=0){//说明还能继续切,当前数字还可以增加
                        return true;
                    }
                   count--;
                   start=i;
                }
        }
        return false;
    }
    static int query_max (int start,int end) {
        int max = Integer.MIN_VALUE;
        int s = start;
        int e = end;
        while(s<=e){
            if(s%2==1) {
                max=Integer.max(tree_max[s],max);
            }
            if(e%2==0) {
                max=Integer.max(tree_max[e],max);
            }
            s=(s+1)>>1;
            e=(e-1)>>1;
        }
        return max;
    }
    static void update_max(int index,int value) {
        while (index>0) {
            if(tree_max[index]<value) {
                tree_max[index] = value;
            }
            index=index>>1;
        }
    }
    public static void initTree(){
        int l=1;
        while (l<N){
            l=l*2;
        }
        tree_max = new int[2*l];//计算出数组的大小
        tree_min = new int[2*l];
        Arrays.fill(tree_min,Integer.MAX_VALUE);
        int fromIndex = l;//这个是实际数据的开始, fromIndex+1 方的是数组里的第一个数字
        findex=fromIndex;
        for (int i = 0; i < arrN.length; i++) {
            int index=fromIndex+i+1;
            int v = arrN[i];
            update_max(index,v);
            update_min(index,v);
        }
    }
    static int query_min (int start,int end) {
        int min = Integer.MAX_VALUE;
        int s = start;
        int e = end;
        while(s<=e){
            if(s%2==1) {
                min=Integer.min(tree_min[s],min);
            }
            if(e%2==0) {
                min=Integer.min(tree_min[e],min);
            }
            s=(s+1)>>1;
            e=(e-1)>>1;
        }
        return min;
    }
    static void update_min(int index,int value) {
        while (index>0) {
            if(tree_min[index]>value) {
                tree_min[index] = value;
            }
            index=index>>1;
        }
    }
    public static int soRan(int start,int end){//计算一个数组区间的费用,前面包含,后面包含
        int min=query_min(start,end);
        int max=query_max(start,end);
        return max-min;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值