第一题

有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?

输入描述:

每个输入包含1哥测试用例。每个测试数据的第一行包含一个证书n(1<=n<=50),表示学生的个数,接下来的一行,包含n个整数,按顺序表示表示学生的能力值ai(-50<=ai<=50)。接下来的一行包含两个整数,k和d(1<=k<=10, 1<=d<=50)。

输出描述:

输出的一行表示最大的乘积。


import java.util.*;
 
public class Main {
      
  public static void main(String args[]){
      Scanner s=new Scanner(System.in);
      int n=s.nextInt();
      int val[]=new int[n+1];
      int i,j;
      for(i=1;i<=n;i++)
          val[i]=s.nextInt();
      int k,d;
      k=s.nextInt();
      d=s.nextInt();
      long mx[][]=new long[n+1][k+1];
      long mn[][]=new long[n+1][k+1];
      for(i=1;i<=n;i++){
          mx[i][1]=mn[i][1]=val[i];
      }
      for(i=2;i<=n;i++){
          for(j=2;j<=k&&i>=j;j++){
              int h;
              long max=Integer.MIN_VALUE;
              long min=Integer.MAX_VALUE;
              for(h=i-1;h>=i-d&&h>=1&&h>=j-1;h--){
                  if(max<mx[h][j-1])
                      max=mx[h][j-1];
                  if(min>mn[h][j-1])
                      min=mn[h][j-1];
              }
              if(val[i]>0){
                  mx[i][j]=val[i]*max;
                  mn[i][j]=val[i]*min;
              }else{
                  mx[i][j]=val[i]*min;
                  mn[i][j]=val[i]*max;
              }
          }
      }
      long max=Integer.MIN_VALUE;
      for(i=n;i>=k;i--)
          if(max<mx[i][k])
              max=mx[i][k];
      System.out.println(max);
  }
  
      
}



第二题

给定一个 n 行 m 列的地牢,其中 '.' 表示可以通行的位置,'X' 表示不可通行的障碍,牛牛从 (x0 , y0 ) 位置出发,遍历这个地牢,和一般的游戏所不同的是,他每一步只能按照一些指定的步长遍历地牢,要求每一步都不可以超过地牢的边界,也不能到达障碍上。地牢的出口可能在任意某个可以通行的位置上。牛牛想知道最坏情况下,他需要多少步才可以离开这个地牢。


import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int n = scanner.nextInt();
            int m = scanner.nextInt();
            char[][] map = new char[n][m];
            for (int i = 0; i < n; i++) {
                String s = scanner.next();
                map[i] = s.toCharArray();
            }
            int x0 = scanner.nextInt();
            int y0 = scanner.nextInt();
            int k = scanner.nextInt();
            int[][] move = new int[k][2];
            for(int i=0;i<k;i++){
                move[i][0] = scanner.nextInt();
                move[i][1] = scanner.nextInt();
            }
            System.out.println(maxStep(n, m, map, x0, y0, k, move));
        }
    }
 
    public static int maxStep(int n, int m, char[][] map, int x0, int y0, int k, int[][] move) {
        int[][] dis = new int[n][m];// 访问标记
        //引入队列是为了遍历到没有出路为止  总结:广度遍历一般都需要队列。
        Queue<Integer> queueX = new LinkedList<Integer>();
        Queue<Integer> queueY = new LinkedList<Integer>();
        queueX.add(x0); // 添加起始位置
        queueY.add(y0);
        dis[x0][y0] = 1;
        while (!queueX.isEmpty() && !queueY.isEmpty()) {
            x0 = queueX.remove();
            y0 = queueY.remove();
            for (int i = 0; i < k; i++) {
                //保证不出界
                if (x0 + move[i][0] >= 0 && x0 + move[i][0] < n && y0 + move[i][1] >= 0 && y0 + move[i][1] < m) {
                    if(dis[x0 + move[i][0]][y0 + move[i][1]] == 0){
                        if(map[x0 + move[i][0]][y0 + move[i][1]] == '.'){
                            queueX.add(x0 + move[i][0]);
                            queueY.add(y0 + move[i][1]);
                            dis[x0 + move[i][0]][y0 + move[i][1]] = dis[x0][y0] + 1;
                        }
                        else{
                            dis[x0 + move[i][0]][y0 + move[i][1]] = -1;
                        }
                    }
                }
            }
        }
        int maxStep = Integer.MIN_VALUE;
        int hasRoad = 1;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(dis[i][j] == 0 && map[i][j] == '.'){
                    hasRoad = 0; //存在没有被访问的“.”说明路径不能遍历完全,有些出口到不了。
                }
                maxStep = Math.max(dis[i][j], maxStep);
            }
        }
        if(hasRoad == 0){
            return -1;
        }
        else{
            return maxStep - 1; // 因为起始步的dis值为1,这里要减去1.
        }
    }
 
}



第三题

牛牛想尝试一些新的料理,每个料理需要一些不同的材料,问完成所有的料理需要准备多少种不同的材料。


import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
 
 
public class Main {
 
    public static Scanner sc = new Scanner(System.in);
    public static void main(String... args){
        int res = test06();
        System.out.println(res);
 
    }
 
     
     
    public static int test01() {
        int len = sc.nextInt();
        int[] inputs = new int[len];
        for(int i=0; i<len; i++){
            inputs[i] = sc.nextInt();
        }
        int start =0;
        int end = len-1;
        int times = 0;
        while(start<=end){
            if(inputs[start]<inputs[end]){
                inputs[++start]+=inputs[start-1];
                times++;
            }else if(inputs[start]>inputs[end]){
                inputs[end--]+=inputs[end+1];
                times++;
            }else{
                start++;
                end--;
            }
        }
        return times;
    }
     
    public static int test02(){
        int res = 0;
        int input = sc.nextInt();
        double r = Math.sqrt(input);
        if(r%1==0){
            res = 4;
        }
         
        for(int i=0;i<r;i++){
            for(int j=0;j<r;j++){
                if(Math.pow(i, 2)+Math.pow(j, 2) == input){
                    res+=4;
                }
            }
        }
         
         
         
        return res;
    }
 
    public static int test03(){
        int res = 0;
        int k = sc.nextInt();
        int m = sc.nextInt();
        int[] minres = new int[m+1];
        for(int i=0;i<m+1;i++){
            minres[i] = 99999;
        }
        aa(k,m,minres,res);
         
        return minres[0];
    }
     
    public static int test04(){
        int res = -1;
        int n = sc.nextInt();
        int[] minres = new int[n+1];
        for(int i=0;i<n+1;i++){
            minres[i] = 9999;
        }
        minres[0] = 0;
         
        for(int i=0;i<n;i++){
            if(i+6<=n){             
                minres[i+6] = Math.min(minres[i+6], minres[i]+1);
            }
            if(i+8<=n){             
                minres[i+8] = Math.min(minres[i+8], minres[i]+1);
            }
        }
        if(minres[n]==9999){
            res = -1;
        }else{
            res = minres[n];
        }
         
         
        return res;
    }
     
    public static int test05(){
        int res = -1;
        int n =sc.nextInt();
        int[] skills = new int[n];
        for(int i=0;i<n;i++){
            skills[i] = sc.nextInt();
        }
        int k = sc.nextInt();
        int d = sc.nextInt();
         
        int[] maxsk = new int[n+1];
        int[] ks = new int[n+1];
        for(int i=0;i<n+1;i++){
            maxsk[i] = 0;
            ks[i] = 0;
        }
        for(int i=0;i<n+1;i++){
             
            for(int j=1;j<=d;j++){
                int tmp = i+j;
                if(tmp<n){  
                    if(maxsk[tmp]>skills[i]*skills[tmp]){
                    }else{
                        ks[tmp] = ks[tmp]+1;
                        maxsk[tmp] = skills[i]*skills[tmp];
                    }  
                     
                }
            }
             
        }
        res = maxsk[n];
        return res;
    }
     
    public static int test06(){
        int res = 0;
        Set<String> sets =new HashSet<String>();
        while(sc.hasNext()){
            sets.add(sc.next());
        }
        res = sets.size();
        return res;
    }
     
     
     
    private static void aa(int k,int m,int[] minres,int res){
        ArrayList yues = getYue(k);
        if(k<m){
             
            for(int i=0;i<yues.size();i++){
                int k2 = k+(Integer)yues.get(i);
                minres[k2] = Math.min(minres[k2], ++res);
                aa(k2,m,minres,res);
                res--;
            }
        }else if(k==m){
            if(--res<minres[0]){
                minres[0] = res;
            }
             
            return;
        }
         
        return;
         
 
    }
     
    private static ArrayList getYue(int num){
        ArrayList arr = new ArrayList();
        for(int i=(int) (Math.sqrt(num)+1);i>1;i--){
            if(num%i==0){
                arr.add(i);
            }
        }
        return arr;
    }
}



第四题

牛牛和 15 个朋友来玩打土豪分田地的游戏,牛牛决定让你来分田地,地主的田地可以看成是一个矩形,每个位置有一个价值。分割田地的方法是横竖各切三刀,分成 16 份,作为领导干部,牛牛总是会选择其中总价值最小的一份田地, 作为牛牛最好的朋友,你希望牛牛取得的田地的价值和尽可能大,你知道这个值最大可以是多少吗?


import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner scan=new Scanner(System.in);
        while(scan.hasNext()){
            int n=scan.nextInt();
            int m=scan.nextInt();
            int[][] matrix=new int[n+1][m+1];
            int[][] sum=new int[n+1][m+1];
            for(int i=1;i<=n;i++){
                String line=scan.next();
                for(int j=1;j<=m;j++){
                    matrix[i][j]=line.charAt(j-1)-'0';
                }
            }
            get_sum(matrix,sum);
            int ans=binarySearch(sum);
            System.out.println(ans);
        }
    }
     
    public static int binarySearch(int[][] sum){
        int l=0, r=sum[sum.length-1][sum[0].length-1]+1;
        int ret=0, mid=0;
        while(l<r){
            mid=(l+r)>>1;
            if(isLeagle(mid,sum)){
                l=mid+1;
                ret=mid;
            }else{
                r=mid;
            }
        }
        return ret;
    }
     
    public static void get_sum(int[][] matrix, int[][] sum){
        for(int i=1;i<matrix.length;i++){
            for(int j=1;j<matrix[0].length;j++){
                sum[i][j]=sum[i][j-1]+sum[i-1][j]+matrix[i][j]-sum[i-1][j-1];
            }
        }
    }
     
    public static int get_aera(int[][] sum, int x1, int y1, int x2, int y2){
        return sum[x2][y2]-sum[x1][y2]-sum[x2][y1]+sum[x1][y1];
    }
     
    public static boolean isLeagle(int val, int[][] sum){
        int n=sum.length-1;
        int m=sum[0].length-1;
        for(int j1=1;j1<=m-3;j1++)
            for(int j2=j1+1;j2<=m-2;j2++)
                for(int j3=j2+1;j3<=m-1;j3++){
                    int pre=0, cnt=0;
                    for(int i=1;i<=n;i++){
                        int a1=get_aera(sum,pre,0,i,j1);
                        int a2=get_aera(sum,pre,j1,i,j2);
                        int a3=get_aera(sum,pre,j2,i,j3);
                        int a4=get_aera(sum,pre,j3,i,m);
                        if(a1>=val&&a2>=val&&a3>=val&&a4>=val){
                            pre=i;
                            cnt++;
                        }
                        if(cnt>=4) return true;
                    }
                }
        return false;
    }
}



第五题

n 只奶牛坐在一排,每个奶牛拥有 ai 个苹果,现在你要在它们之间转移苹果,使得最后所有奶牛拥有的苹果数都相同,每一次,你只能从一只奶牛身上拿走恰好两个苹果到另一个奶牛上,问最少需要移动多少次可以平分苹果,如果方案不存在输出 -1。


import java.util.*;
 
public class Main {
      
  public static void main(String args[]){
      Scanner s=new Scanner(System.in);
      int n=s.nextInt();
      int i,j,a[]=new int[n];
      for(i=0;i<n;i++)
          a[i]=s.nextInt();
      int sum=0;
      for(i=0;i<n;i++)
          sum+=a[i];
      if(sum%n!=0){
          System.out.println(-1);
          return;
      }
      int avg=sum/n;
      for(i=0;i<n;i++)
          a[i]=a[i]-avg;
      int num=0;
      for(i=0;i<n;i++)
          if(a[i]%2!=0){
              System.out.println(-1);
              return;
          }else{
              if(a[i]>0)
                  num+=a[i]/2;
          }
      System.out.println(num);
       
  }
  
      
}



第六题

航天飞行器是一项复杂而又精密的仪器,飞行器的损耗主要集中在发射和降落的过程,科学家根据实验数据估计,如果在发射过程中,产生了 x程度的损耗,那么在降落的过程中就会产生 x2 程度的损耗,如果飞船的总损耗超过了它的耐久度,飞行器就会爆炸坠毁。问一艘耐久度为 h 的飞行器,假设在飞行过程中不产生损耗,那么为了保证其可以安全的到达目的地,只考虑整数解,至多发射过程中可以承受多少程度的损耗?


import java.util.*;
import java.math.*;
public class Main {
 
     
    public static void main(String[] args) {
        // TODO Auto-generated method stub
     
        Scanner scan=new Scanner(System.in);
         
        long n=scan.nextLong();
        long s=(long)Math.sqrt(n);
        if(s*(s+1)>n)
            System.out.println(s-1);
        else
            System.out.println(s);
         
}
}



第七题

牛牛拿到了一个藏宝图,顺着藏宝图的指示,牛牛发现了一个藏宝盒,藏宝盒上有一个机关,机关每次会显示两个字符串 s 和t,根据古老的传说,牛牛需要每次都回答 t 是否是 s 的子序列。注意,子序列不要求在原字符串中是连续的,例如串 abc,它的子序列就有{空串, a, b, c, ab, ac, bc, abc} 8 种。


import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
         Scanner in = new Scanner(System.in);
         while(in.hasNext()){
             String s1 = in.next();
             String s2 = in.next();
             int i = 0,j = 0;
             while( i<s1.length() && j<s2.length() ){
                 if(s1.charAt(i) == s2.charAt(j)){
                     i++;j++;
                 } else {
                     i++;
                 }
             }
             if(j == s2.length() ){
                 System.out.println("Yes");
             } else {
                 System.out.println("No");
             }
         }
         in.close();
    }
}



第八题

牛牛的作业薄上有一个长度为 n 的排列 A,这个排列包含了从1到n的n个数,但是因为一些原因,其中有一些位置(不超过 10个)看不清了,但是牛牛记得这个数列顺序对的数量是 k,顺序对是指满足 i < j 且 A[i] < A[j] 的对数,请帮助牛牛计算出,符合这个要求的合法排列的数目。


import java.util.*;
public class Main{
    private static int n,k, missNum;
    private static int[] arr=new int[100];
    private static boolean[] exist=new boolean[101];
    private static int[][] leftCnt=new int[100][10];
    private static int[][] rightCnt=new int[100][10];
    private static int[] tofill=new int[10];
     
    public static void main(String[] args){
 
        Scanner scan=new Scanner(System.in);
        while(scan.hasNext()){
            Arrays.fill(exist,false);
            Arrays.fill(arr,0);
            Arrays.fill(tofill,0);
            for(int i=0;i<100;i++){
                Arrays.fill(leftCnt[i],0);
                Arrays.fill(rightCnt[i],0);
            }
            missNum=0;
            n=scan.nextInt();
            k=scan.nextInt();
            for(int i=0;i<n;i++){
                arr[i]=scan.nextInt();
                if(arr[i]!=0)
                    exist[arr[i]]=true;
            }
            int index=0;
            for(int i=1;i<=n;i++){
                if(!exist[i]){
                    tofill[index++]=i;
                    missNum++;
                }
            }
            int ans=solve();
            System.out.println(ans);
        }
 
 
 
 
    }
     
    public static int get_pair(int[] tofill){
        int length=missNum;
        int ret=0;
        for(int i=0;i<length-1;i++)
            for(int j=i+1;j<length;j++)
                if(tofill[i]<tofill[j])
                    ret++;
        return ret;
    }
     
    public static void swap(int[] arr, int i, int j){
        int temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static int factor(){
        int ret=1;
        for(int i=1;i<=missNum;i++)
            ret*=i;
        return ret;
    }
     
    public static void next_permutation(int[] tofill){
        int length=missNum;
        int index=length-2;
        while(index>=0&&tofill[index]>tofill[index+1])
            index--;
        if(index<0){
            int i=0,j=length-1;
            while(i<j)
                swap(tofill,i++,j--);
            return;
        }
        int index2=index+1;
        while(index2<length&&tofill[index2]>tofill[index])
            index2++;
        index2--;
        swap(tofill,index,index2);
        index++;
        index2=missNum-1;
        while(index<index2){
            swap(tofill,index,index2);
            index++;
            index2--;
        }
        return;
    }
     
    public static int solve(){
        int cnt1=0;
        for(int i=0;i<n-1;i++)
            for(int j=i+1;j<n;j++){
                if(arr[i]==0) continue;
                if(arr[i]<arr[j]) cnt1++;
            }
        for(int i=0;i<missNum;i++){
            int cnt=0,index=0;
            for(int j=0;j<n;j++){
                if(arr[j]!=0){
                    if(arr[j]<tofill[i]) cnt++;
                }else
                    leftCnt[tofill[i]][index++]=cnt;
            }
        }
        for(int i=0;i<missNum;i++){
            int cnt=0, index=missNum-1;
            for(int j=n-1;j>=0;j--){
                if(arr[j]!=0){
                    if(arr[j]>tofill[i]) cnt++;
                }else
                    rightCnt[tofill[i]][index--]=cnt;
            }
        }
        int ans=0;
        int times=0;
        int limit=factor();
        do{
            int cnt2=get_pair(tofill);
            int cnt=cnt1+cnt2;
            for(int i=0;i<missNum;i++)
                cnt+=leftCnt[tofill[i]][i]+rightCnt[tofill[i]][i];
            if(cnt==k) ans++;
            times++;
            next_permutation(tofill);
        }while(times<limit);
        return ans;
    }
}