算法训练第二周题解汇总

总结:这周题组给我的感觉是数据规模都比较小,都可以考虑暴力

A - AABCC

[ABC300D] AABCC - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解: 就是纯暴力题,由于 a<b<c,所以a^{5}≤N,a<500;c^{2}<=N,c<10^{6}。先用埃筛预处理,然后枚举的时候剪枝

import java.util.Arrays;
import java.util.Scanner;

/*
 *@filename: Main
 *@author: lyh
 *@date:2023/5/3 10:26
 *@version 1.0
 *@description TODO
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long n = scanner.nextLong();
        int[] book = new int[1000001];
        Sieve(book);//预处理
        long ans = 0;
        for (int a = 2; a < 500; a++) {
            if (book[a] == 1) {
                continue;
            }
            if((long) a *a*a*a*a>n)break;
            for (int b = a + 1; b < 1000000; b++) {
                if (book[b] == 1) {
                    continue;
                }
                if((long) a *a*b*b*b>n)break;
                for (int c = b + 1; c < 1000000; c++) {
                    if (book[c] == 1) {
                        continue;
                    }
                    long value = (long)a * a * b * c * c;
                    if (value <= n) {
                        ans++;
                    } else {
                        break;
                    }
                }
            }
        }
        System.out.println(ans);
    }

    public static void Sieve(int[] book) {//埃筛
        Arrays.fill(book, 0);
        for (int i = 2; i * i <= 1000000; i++) {
            if (book[i] == 0) {
                for (int j = i * i; j <= 1000000; j = j + i) {
                    book[j] = 1;
                }
            }
        }
    }
}

B - Same Map in the RPG World

[ABC300B] Same Map in the RPG World - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解: 因为H、W的范围都比较小,所以可以暴力解决,时间复杂度O(H^2W^2)。因为是循环的,所以我在构造矩阵的时候,将左右连通,上下连通(取余也可以)。将左上角的第一个点看成矩阵的起点,每移动一次就比较是否与矩阵B相等。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/*
 *@filename: Main
 *@author: lyh
 *@date:2023/5/3 10:26
 *@version 1.0
 *@description TODO
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int h=scanner.nextInt();
        int w=scanner.nextInt();
        List<String> list1=new ArrayList<>();
        for(int i=0;i<h;i++){
            String s=scanner.next();
            s=s+s;//左右连通
            list1.add(s);
        }
        for(int i=0;i<h;i++){//上下连通
            list1.add(list1.get(i));
        }
        List<String> list2=new ArrayList<>();
        for(int i=0;i<h;i++){
            String s=scanner.next();
            list2.add(s);
        }
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                if(check(i,j,list1,list2,h,w)){
                    System.out.println("Yes");
                    return;
                }
            }
        }
        System.out.println("No");
    }
    public static boolean check(int i,int j,List<String>list1,List<String>list2,int h,int w){
        boolean flag=true;
        //以i,j为起点的矩阵,循环遍历与第二个矩阵相比较
        for(int a1=i,a2=0;a1<i+h;a1++,a2++){
            for(int b1=j,b2=0;b1<j+w;b1++,b2++){
                if(list1.get(a1).charAt(b1)!=list2.get(a2).charAt(b2)){
                    flag=false;
                    return flag;
                }
            }
        }
        return flag;
    }
}

C - Cross

[ABC300C] Cross - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解:看数据范围比较小,这题也能直接暴力。遍历矩阵,一旦遇到一个'#',就以他为中心搜索它的周围,看他是否能够成一个十字架,取最长的长度。题目保证不会有两个十字架之间共享一个角的情况出现

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/*
 *@filename: Main
 *@author: lyh
 *@date:2023/5/3 10:26
 *@version 1.0
 *@description TODO
 */
public class Main {
    private static final int[][] next={{1,1},{-1,-1},{-1,1},{1,-1}};
    private static int h;
    private static int w;
    public static void main(String[] args) {

        Scanner scanner=new Scanner(System.in);
        h=scanner.nextInt();
        w=scanner.nextInt();
        int lenth=Math.min(h,w);
        int[] ans=new int[lenth+1];
        List<String>list=new ArrayList<>();
        for(int i=0;i<h;i++){
            String s=scanner.next();
            list.add(s);
        }
        for(int i=0;i<h;i++){
            for(int j=0;j<w;j++){
                if(list.get(i).charAt(j)=='#'){
                    int size=get(i,j,list);
                    ans[size]++;
                }
            }
        }
        for(int i=1;i<=lenth;i++){
            System.out.print(ans[i]+" ");
        }
        System.out.println();
    }
    public static int get(int i,int j,List<String>list){
        int size=1;
        while(true){
            for(int a=0;a<4;a++){
                int dx=i+next[a][0]*size;
                int dy=j+next[a][1]*size;
                if(dx<0||dy<0||dx>=h||dy>=w||list.get(dx).charAt(dy)=='.'){
                    return size-1;
                }
            }
            size++;
        }
    }
}

D - Find by Query  

[ABC299D] Find by Query - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

因为本题是一个交互题,交互格式如下:

题解:题目说最多问20个问题,为什么限定在这个数字呢?实际上容易发现这个数差不多是log n级别的,我们首先想到二分做法。

因为这个序列只有两种数字,0 或 1。不难发现,假如有一段区间S(left),S(left)+1​,S(left)+2​……S(right),只要 S(left) !=S(right)​,那么无论中间是什么数,总会找到答案。而题目给出S1=0和Sn​=1,首先把 l 指针指向第一个位置,r 指针指向最后一个位置。接下来我们要做的是维护这两个指针并时刻满足 S(l)​=0 且S(r) =1。在最终必定会有一个时刻,R=L+1,此时直接得到答案为 L。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int left=1,right=n;
        while(left+2<=right){//left和right存在≤1个元素时
            int mid=(left+right)>>1;
            System.out.println("?"+mid);
            String midEle=scanner.next();
            if(midEle.charAt(0)=='0')left=mid;
            else right=mid;
        }
        System.out.println("!"+left);
    }
}

E - Dango 

[ABC299C] Dango - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解:非常简单的一个题,遍历一遍字符串,当碰到 '-' 时就分别向前、向后搜索 'o',不断取最大值。


import java.util.Scanner;

/*
 *@filename: Test
 *@author: lyh
 *@date:2023/5/7 9:28
 *@version 1.0
 *@description TODO
 */
public class Main{
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        String s=scanner.next();
        int ans=-1;
        for(int i=0;i<n;i++){
            if(s.charAt(i)=='-'){
                int index=i-1,onum=0;
                while(index>=0&&s.charAt(index)=='o'){
                    onum++;
                    index--;
                }
                if(onum>0)ans=Math.max(onum,ans);
                index=i+1;
                onum=0;
                while(index<n&&s.charAt(index)=='o'){
                    onum++;
                    index++;
                }
                if(onum>0)ans=Math.max(onum,ans);
            }
        }
        System.out.println(ans);
    }
}

F - Cards Query Problem 

[ABC298C] Cards Query Problem - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解:很简单的模拟题,没什么好说的 

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int q = scanner.nextInt();
        List<List<Integer>>list=new ArrayList<>(n+1);//盒子的集合,盒子里存着数字
        for(int i=0;i<=n;i++)list.add(new ArrayList<>());
        HashMap<Integer,TreeSet<Integer>>map=new HashMap<>();//key为数字,value为所在盒子的有序集合
        for(int a=0;a<q;a++){
            int op=scanner.nextInt();
            switch (op){
                case 1:
                    int i=scanner.nextInt();
                    int j=scanner.nextInt();
                    list.get(j).add(i);
                    if(!map.containsKey(i)){
                        TreeSet<Integer>value=new TreeSet<>();
                        value.add(j);
                        map.put(i,value);
                    }
                    map.get(i).add(j);
                    break;
                case 2:
                    i=scanner.nextInt();
                    List<Integer>box=list.get(i);
                    Collections.sort(box);
                    for (Integer e:box) {
                        System.out.print(e+" ");
                    }
                    System.out.println();
                    break;
                case 3:
                    i=scanner.nextInt();
                    TreeSet<Integer>box2=map.get(i);
                    for(Integer e:box2){
                        System.out.print(e+" ");
                    }
                    System.out.println();
                    break;
            }

        }
    }
}

H - Writing a Numeral 

[ABC298D] Writing a Numeral - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解:刚开始ans=1,

  • 如果是 1 操作, ans = ans * 10 + x 

  • 如果是 2 操作,我们先获取 ans 的首位数字,并且获取它的所在位(从右往左),分别存储到 x,y,最后 ans 减去 x * pow(10, y - 1) 即可。当然这里的pow需要用快速幂(需要用long,因为很可能会出现两个大质数相乘超int)。还要特别注意的是,这里在减了之后有可能ans是负的,我们需要将ans调回正数,注意在加上mod(998244353)之前还要取模一次,因为很可能加上一次后还是负的,所以要先取模

  • 如果是 3 操作,直接输出即可
import java.util.*;

public class Main {
    private static final int mod=998244353;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        List<Long>list=new LinkedList<>();
        list.add(1L);
        long value=1;
        int q=scanner.nextInt();
        for(int i=0;i<q;i++){
            int op=scanner.nextInt();
            switch (op){
                case 1:
                    long x=scanner.nextLong();
                    list.add(x);
                    value=(value*10%mod+x)%mod;
                    break;
                case 2:
                    value=(mod+(value-pow(list.size()-1)*list.get(0))%mod)%mod;//防止value为负,特别注意在加上mod之前还要取模一次,因为很可能加上一次后还是负的,所以要先取模
                    list.remove(0);
                    break;
                case 3:
                    System.out.println(value%mod);
                    break;
            }
        }
    }
    public static long pow(int num){//快速幂,这里需要用long,因为很可能会出现两个大质数相乘超int
        long result=1,base=10;
        while (num>0){
            if(num%2==1)result=result*base%mod;
            num/=2;
            base=base*base%mod;
        }
        return result;
    }
}

J - M<=ab

[ABC296D] M<=ab - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

大意:

题解:首先根据数据范围选择long类型,从小到大枚举 a,再求出最小的 b,若 a <= n && b <= n,则此对 a,b 满足条件,更新答案。需要注意的是我们在枚举a的时候,要将 for 循环中的 m 改成 m * 2,如果为m的话,枚举 a 时离正确答案可能会小一点点,比方说当N、M分别为4、15时,

a 只会枚举到 ​\sqrt{15},也就是 3。 当 a=3 时,b=5,即 b 不满足条件。但实际上我们a,b都取4的话是满足条件的。所以这里需要将m 改成 m * 2

import java.util.Scanner;

/*
 *@filename: Main
 *@author: lyh
 *@date:2023/5/3 10:26
 *@version 1.0
 *@description TODO
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long n=scanner.nextLong();
        long m=scanner.nextLong();
        long ans=Long.MAX_VALUE;
        for(long i=1;i*i<=m*2;i++){//m*2
            long j;
            if(m%i==0)j=m/i;
            else j=m/i+1;
            if(i<=n&&j<=n)ans=Math.min(ans,i*j);
        }
        if(ans!=Long.MAX_VALUE) System.out.println(ans);
        else System.out.println(-1);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值