B~G Java题解,代码中已去掉冗余

B %%%

目标是尽量把n保持在最大的可能得值,才能保持次数最多,那么最大的除数肯定是大于n的一半的,时间复杂度O(Tlogn)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            long n=sc.nextLong();
            int ans=0;
            while(n!=0){
                n=n/2-1+n%2;
                ans++;
            }
            System.out.println(ans);
        }
    }
}

C 迷宫

利用并查集,先合并连通块,假如起终点是联通的,就代表无需激光,,否则遍历格子,每个格子是否存在邻居是跟终点相连的,并标记这一行以及这一列,,再遍历第二次,遇到跟起点联通并且行或者列跟终点连通的各自直接返回YES,,时间复杂度O(nm)

import java.util.*;
public class Main{
    static int move[][]={{0,1},{0,-1},{1,0},{-1,0}};
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt(),m=sc.nextInt(),group[]=new int[n*m],start=-1,end=-1;
        char c[][]=new char[n][];
        for(int i=0;i<n;i++){
            c[i]=sc.next().toCharArray();
            for(int j=0;j<m;j++){
                group[i*m+j]=i*m+j;
                if(c[i][j]=='S'){
                    start=i*m+j;
                }
                else if(c[i][j]=='E'){
                    end=i*m+j;
                }
            }
        }
        //寻找连通块:
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(c[i][j]!='#'){
                    for(int mo[]:move){
                        int x=i+mo[0],y=j+mo[1];
                        if(x>=0&&x<n&&y>=0&&y<m&&c[x][y]!='#'){
                            union(i*m+j,x*m+y,group);
                        }
                    }
                }
            }
        }
        if(find(start,group)==find(end,group)){
            //不需要用激光
            System.out.println("YES");
        }
        else{
            boolean row[]=new boolean[n],col[]=new boolean[m];
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    for(int mo[]:move){
                        int x=i+mo[0],y=j+mo[1];
                        if(x>=0&&x<n&&y>=0&&y<m&&find(x*m+y,group)==find(end,group)){
                            row[i]=col[j]=true;
                        }
                    }
                }
            }
            for(int i=0;i<n;i++){
                for(int j=0;j<m;j++){
                    if(find(i*m+j,group)==find(start,group)&&(row[i]||col[j])){
                        System.out.println("YES");
                        return;
                    }
                }
            }
            System.out.println("NO");
        }
    }
    static void union(int a,int b,int group[]){
        group[find(b,group)]=find(a,group);
    }
    static int find(int a,int group[]){
        if(a!=group[a]){
            group[a]=find(group[a],group);
        }
        return group[a];
    }
}

D 又是一年毕业季

若存在任何人的时间间隔都除不尽的最小数,一定是质数,质数不可能大于第n+1个,因此筛出前2e5个质数,再进行判断,找出每组中最小不存在的质数,时间复杂度O(ClogC+Tn),其中C==3e6

import java.util.*;
public class Main{
    public static void main(String args[]){
        boolean notPrime[]=new boolean[(int)3e6];
        List<Integer> prime=new ArrayList<>();
        for(int i=2;i<3e6;i++){
            if(!notPrime[i]){
                prime.add(i);
                for(int j=i*2;j<3e6;j+=i){
                    notPrime[j]=true;
                }
            }
        }
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            int n=sc.nextInt();
            Set<Integer> set=new HashSet<>();
            for(int j=0;j<n;j++){
                set.add(sc.nextInt());
            }
            for(int a:prime){
                if(!set.contains(a)){
                    System.out.println(a);
                    break;
                }
            }
        }
    }
}

E 多米诺骨牌

有些骨牌可以导致连锁反应,因此可以区间合并,只推起头的那个,时间复杂度O(Tnlogn)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            int n=sc.nextInt(),m=sc.nextInt(),h[]=new int[n],x[]=new int[n],ans=0;
            Integer idx[]=new Integer[n];
            for(int j=0;j<n;j++){
                h[j]=sc.nextInt();
                idx[j]=j;
            }
            for(int j=0;j<n;j++){
                x[j]=sc.nextInt();
            }
            Arrays.sort(idx,(a,b)->Integer.compare(x[a],x[b]));
            Queue<Integer> q=new PriorityQueue<>((a,b)->Integer.compare(b,a));
            for(int j=0,k=1;j<n;){
                int max=x[idx[j]]+h[idx[j]];
                while(k<n&&max>=x[idx[k]]){
                    max=Math.max(max,x[idx[k]]+h[idx[k]]);
                    k++;
                }
                q.add(k-j);
                j=k;
            }
            for(int j=0;j<m&&!q.isEmpty();j++){
                ans+=q.poll();
            }
            System.out.println(ans);
        }
    }
}

F 自爆机器人

总的可能得距离等于最短距离加上在某两堵墙之间来回的距离,那么可以等同于在相邻的墙之间来回,这样的距离种数最多有sqrt(n)种,因此采用背包来计算,时间复杂度O(Ttsqrt(n))

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int T=sc.nextInt();
        for(int i=0;i<T;i++){
            int n=sc.nextInt(),m=sc.nextInt(),t=sc.nextInt(),x[]=new int[m];
            for(int j=0;j<m;j++){
                x[j]=sc.nextInt();
            }
            if(n>t){
                System.out.println("0");
            }
            else{
                Arrays.sort(x);
                boolean has[]=new boolean[n*2+5],dis[]=new boolean[t-n+1];
                dis[0]=true;
                for(int j=1;j<m;j++){
                    has[(x[j]-x[j-1])*2]=true;
                }
                for(int j=0;j<=n*2;j+=2){
                    if(has[j]){
                        for(int k=j;k<=t-n;k++){
                            dis[k]|=dis[k-j];
                        }
                    }
                }
                for(int j=t-n;;j--){
                    if(dis[j]){
                        System.out.println(j+n);
                        break;
                    }
                }
            }
        }
    }
}

G 大鱼吃小鱼

优先队列维护此时的鱼,离散化并用树状数组记录每一段的总重量,二分找到每一次吃的最大值,O(能过)

import java.util.*;
public class Main{
    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        int t=sc.nextInt();
        for(int i=0;i<t;i++){
            int n=sc.nextInt(),x=sc.nextInt(),weight[]=new int[n+5],p=1;
            TreeSet<Integer> set1=new TreeSet<>(),set2=new TreeSet<>();
            Queue<int[]> q1=new PriorityQueue<>((a,b)->Integer.compare(a[0],b[0])),q2=new PriorityQueue<>((a,b)->Integer.compare(a[1],b[1]));
            for(int j=0;j<n;j++){
                int l=sc.nextInt(),r=sc.nextInt(),y=sc.nextInt();
                q1.add(new int[]{l,r,y});
                set1.add(y);
                set2.add(l);
                set2.add(r);
            }
            Map<Integer,Integer> map=new HashMap<>();
            for(int a:set1){
                weight[p]=a;
                map.put(a,p);
                p++;
            }
            long count[]=new long[n+5],ans=x;
            for(int a:set2){
                while(!q2.isEmpty()&&q2.peek()[1]<=a){
                    int b[]=q2.poll();
                    update(count,map.get(b[2]),-b[2]);
                }
                while(!q1.isEmpty()&&q1.peek()[0]<=a){
                    int b[]=q1.poll();
                    update(count,map.get(b[2]),b[2]);
                    q2.add(b);
                }
                int maxIdx=0;
                long cur=x;
                while(maxIdx<p-1){
                    int l=maxIdx+1,r=p-1;
                    if(weight[l]>cur){
                        break;
                    }
                    while(l<r){
                        int mid=(l+r)>>1;
                        if(weight[mid]<=cur){
                            l=mid;
                        }
                        else{
                            r=mid-1;
                        }
                        if(l==r-1){
                            if(weight[r]<=cur){
                                l=r;
                            }
                            break;
                        }
                    }
                    cur=x+get(count,l);
                    maxIdx=l;
                }
                ans=Math.max(ans,cur);
            }
            System.out.println(ans);
        }
    }
    static long get(long count[],int idx){
        long ans=0;
        for(int i=idx;i!=0;i&=i-1){
            ans+=count[i];
        }
        return ans;
    }
    static void update(long count[],int idx,int inc){
        for(int i=idx;i<count.length;i+=i&-i){
            count[i]+=inc;
        }
    }
}