当前位置: 首页 > news >正文

牛客周赛85 DEF Java

牛客周赛85 DEF Java

  • D小紫的优势博弈
  • E小紫的线段染色
  • F小紫的树上染色

D小紫的优势博弈

在这里插入图片描述

思路:枚举小红的所有情况,删除前1个,删除前2个 … 全部删除。这样得到了小紫的所有情况,然后从删除位置的后一个往后面数出现的‘0’和‘1’的个数,如果全是偶数就小紫赢。

这题我的思路是没问题:但是用了substring(),它的时间复杂度是O(k),这样一来总的时间复杂度是O(N*N) N=1e6,超出时间限制。其实没不必要用substring,内层循环直接这么写:for(int j=i;j<n;j++),一回事,这样时间复杂度降低了一点,也就通过了。

下面是超时代码:
在这里插入图片描述

修改后代码:

import java.util.*;
public class Main {
    public static void main(String[]args){
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();//表示长度
        String s=scan.next();
        int cnt=0;
        int cnt0=0;
        int cnt1=0;
        for(int i=1;i<n;i++){
            cnt0=0;
            cnt1=0;
            for(int j=i;j<n;j++){
                if(s.charAt(j)=='0'){
                    cnt0++;
                }else{
                    cnt1++;
                }
                
                if(cnt0%2==0&&cnt1%2==0){
                    cnt++;
                    break;
                }
            }
        }
        double res=cnt*1.0/n;
        System.out.print(res);
    }   
}

E小紫的线段染色

在这里插入图片描述

思路:
1.创建一个集合收集所有线段,该集合的元素类型是int类型的数组{l,r,次序}。
2.对所有线段排序,如果左边界不相同就按照左边界从小到大排序,左边界同,就按照右边界从小到大排序。
3.创建两个变量来记录此时最后红色线段的尾位置hongEnd和最后紫线段的尾位置ziEnd
4.遍历所有线段,更新hongEnd和ziEnd,把涂成紫色的线段需要放入结果集合res中,最后看结果集合就可以了。

注意:优先选择ArrayList,因为LinkedList的get时间复杂度O(K)。

import java.util.*;
public class Main {
    public static void main(String[]args){
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();//表示线段的数量
        //创建一个集合,元素类型是int型的数组,{l,r,次序},不能用LinkedList 因为get的时间复杂度尾O(K)
        ArrayList<Integer[]> list=new ArrayList();
        for(int i=0;i<n;i++){
            int l=scan.nextInt();
            int r=scan.nextInt();
            list.add(new Integer[]{l,r,i+1});
        }
        //对排序:如果两条线段的左边界相同,就按照右边界从小到大排序,如果左边界不同你就按照左边界从小到大排序
        Collections.sort(list,(o1,o2)->{//O(N*logN)
            if(o1[0].equals(o2[0])){
                return Integer.compare(o1[1],o2[1]);
            }else{
                return Integer.compare(o1[0],o2[0]);
            }
        });
        //创建存放结果的集合
        ArrayList<Integer> res=new ArrayList();
        //记录最后红色线段的尾位置
        int hongEnd=list.get(0)[1];
        //记录最后子线段的尾位置
        int ziEnd=-1;
        //遍历所有线段
        for(int i=1;i<n;i++){
            int curStart=list.get(i)[0];
            int curEnd=list.get(i)[1];
            //当前的线段是红色
            //有两种情况:1.当前的lefe<=hongEnd,就必须染成紫色。确定了要染成紫色,需要看看ziEnd是否<left,如果>left,就紫色相交了
            //2.当前的left大于hongend,就保持红色就好
            if(curStart<=hongEnd){
                //染成紫色
                if(curStart>ziEnd){
                    //可以染
                    res.add(list.get(i)[2]);
                    ziEnd=curEnd;
                }else{
                    //紫色相交了
                    System.out.print(-1);
                    return;
                }
            }else{
                //保持红色
                hongEnd=curEnd;
            }
        }
       if(res.size()==0) {
    		res.add(1);
    	}
        System.out.println(res.size());
    	for(Integer i:res) {
    		System.out.print(i+" ");
    	}
    }   
}


F小紫的树上染色

在这里插入图片描述

思路:题目求最大红色联通块的最小值,像这种用二分,最大红色块最小为0,最大为节点个数n,所以l=0,r=n。check(mid,k)定义为:在染紫次数<=k时,能使得最大红色联通块的个数为mid就返回true。check(mid,k)的具体操作:遍历这个无向图,从叶子结点开始(贪心思想),当该节点联通数量>mid就染紫色,记录一共染了多少个紫色,如果<=k就返回true。
步骤:
1.创建图,visit数组(遍历无向图用到),s数组(s[i]:与i节点联通的红色节点个数,加上自己)。
2.创建两个变量 l,r,开始二分查找。

import java.util.*;
public class Main {
    public static void main(String[]args){
        Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();//节点个数
        int k=scan.nextInt();//最多染成紫色的个数
        visit=new boolean[n+1];
        //创建图
        graph=new ArrayList[n+1];
        for(int i=0;i<=n;i++) {
        	graph[i]=new ArrayList<>();
        }
        for(int i=1;i<n;i++){
            int a=scan.nextInt();
            int b=scan.nextInt();
            graph[a].add(b);
            graph[b].add(a);
        }
        s=new int[n+1];
        int l=0,r=n;
        while(l<r){
            int mid=(l+r)>>1;
        	need=0;
        	Arrays.fill(visit, false);
        	Arrays.fill(s, 0);
            
            if(check(mid,k)){//在<=k的机会内,使得最大红色联通块为mid
                r=mid;
            }else{
                l=mid+1;
            }
        }
        System.out.println(l);
    }   
    static ArrayList<Integer>[] graph;
    static int need;//需要的紫色个数
    static int[]s;//s[i]:与以i节点联通的红色节点个数加上自己
    
    //定义: 在<=k的机会之内,是否能让最大红色联通块大小为mid
    static boolean check(int mid,int k){
    	//从节点1开始遍历图
        dfs(1,mid,k);
        return need<=k;
    }
    
    static boolean visit[];//避免走回头路
    
    static void dfs(int root,int mid,int k) {
    	visit[root]=true;
    	for(int neibor:graph[root]) {
    		if(visit[neibor]) {
    			continue;
    		}
    		dfs(neibor,mid,k);
    		//后序位置
    		s[root]+=s[neibor];
    	}
    	//加上自己
    	s[root]++;
    	//判断红色联通块的数量是否大于mid
    	if(s[root]>mid) {
    		//染紫色
    		need++;
    		s[root]=0;
    	}
    }
}

相关文章:

  • 深度学习【迭代梯度下降法求解线性回归】
  • 在 macOS Sequoia 15.2 中启用「三指拖动」并实现快速复制的完整指南 ✨
  • 深度学习-简介
  • 学生选课管理系统数据库设计报告
  • Git下载安装(保姆教程)
  • torcharrow gflags版本问题
  • 动作捕捉手套如何让虚拟现实人机交互 “触手可及”?
  • 【入门初级篇】窗体的基本操作与功能介绍
  • 分布式唯一ID
  • Linux FILE文件操作2- fopen、fclose、fgetc、fputc、fgets、fputs验证
  • Java 大视界 -- Java 大数据机器学习模型的对抗攻击与防御技术研究(137)
  • 【嵌入式】复刻SQFMI开源的Watchy墨水屏电子表——(2)软件部分
  • Git 的使用上传下载和更新
  • 【数学 线性代数】差分约束
  • Python----计算机视觉处理(Opencv:图像颜色替换)
  • 三维重建(十七)——obj文件解读+ply文件解读
  • 搞了搞Python,写了个图片对比程序及AI硅基流动对话
  • BFF与API Gateway的区别解析
  • Socket 、WebSocket、Socket.IO详细对比
  • Dify 搭建
  • 股价两天涨超30%,中航成飞:不存在应披露而未披露的重大事项
  • 国家卫健委:有条件的二级及以上综合医院要开设老年医学科
  • 专访|高圆圆:像鸟儿一样,柔弱也自由
  • 司法部:建立行政执法监督企业联系点,推行行政执法监督员制度
  • 一季度全国消协组织为消费者挽回经济损失23723万元
  • 法治日报:商品明细是隐私,外卖员快递员不应知晓