2020-2021年度第二届全国大学生算法设计与编程挑战赛 (秋季赛)——正式赛

本文分享了编程竞赛中的数位DP技巧、兰德索尔杯比赛的模拟策略,以及大数据分析的简洁方法。同时探讨了数学在解题中的应用,如何最大化问题的解决方案,以及面对海量数据时的有效处理。文章还涉及了Java编程中处理超时问题的技巧,如优化输入输出以提高效率。
摘要由CSDN通过智能技术生成

目录

B题-数位dp

D题-兰德索尔杯-cup

F题-大数据分析

G题-数学math

H题-最大化

I题-小x的好路-road


B题-数位dp

思路:写个方法判断一下就可以了,满足要求的就累加个数。AC代码如下:

public class Main {
    public static void main(String[] args) {
        int ans = 0 ;
        for(int i=13930; i<=457439; i++){
            if(dp(i)){
                ans ++ ;
            }
        }
        System.out.println(ans);
    }
    private static boolean dp(int x){
        String s = String.valueOf(x) ;
        int first = s.charAt(0) - '0' ;
        int last = s.charAt(s.length()-1) - '0' ;
        if(Math.abs(first-last)<=2){
            return false ;
        }
        for(int i=1; i<s.length(); i++){
            int m = s.charAt(i-1) - '0' ;
            int n = s.charAt(i) - '0' ;
            if(Math.abs(m-n)>7){
                return false ;
            }
        }
        return true ;
    }
}

D题-兰德索尔杯-cup

思路:细心一点模拟整个过程就可以,注意细节,我起初一直AC不了,竟然把四个数字换行打印了,无语,人家明明放在一行好吧,我这是咋啦,不说了,AC代码奉上。

import java.util.Scanner;

public class Main {
    static int n ;
    static String [] s ;
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        n = input.nextInt()  ;
        s = new String [4] ;

        for(int i=0; i<4; i++){
            s[i] = input.next() ;
        }
        double acc , ans ;
        for(int j=0; j<4; j++) {
            ans = acc= 0 ;
            for (int i = 0; i < s[j].length(); i++) {
                if(s[j].charAt(i)=='>'){
                    ans += 0.5 ;
                    acc = 4.5 ;
                    continue;
                }
                if(s[j].charAt(i)=='.' && acc >0){
                    if(acc>=0.5) {
                        ans += 0.5;
                        acc -= 0.5;
                    }else{
                        ans += acc + (1- acc*2) ;
                        acc = 0 ;
                    }
                    continue;
                }
                if(s[j].charAt(i)=='.' && acc <= 0){
                    ans += 1 ;
                    continue;
                }
                if(s[j].charAt(i)=='w' && acc >0){
                    if(acc>=1) {
                        ans += 1;
                        acc--;
                    }else{
                        ans += acc + (1-acc)*2 ;
                        acc = 0 ;
                    }
                    continue;
                }
                if(s[j].charAt(i)=='w' && acc <=0){
                    ans += 2 ;
                    continue;
                }

                if(s[j].charAt(i)=='s'){
                    ans ++ ;
                    acc-- ;
                    if(acc>0){
                        if(acc>=0.5) {
                            ans += 0.5;
                            acc -= 0.5;
                        }else{
                            ans += acc + (1- acc*2) ;
                            acc = 0 ;
                        }
                    }else{
                        ans += 1 ;
                    }
                }

                if(s[j].charAt(i)=='m'){
                    ans += 2 ;
                    acc -= 2 ;
                    if(acc>0){
                        if(acc>=0.5) {
                            ans += 0.5;
                            acc -= 0.5;
                        }else{
                            ans += acc + (1- acc*2) ;
                            acc = 0 ;
                        }
                    }else{
                        ans += 1 ;
                    }
                }
            }
            System.out.printf("%.1f ",ans);

        }
    }
}

当然了,这样写,也是可以的,一样的思路。

import java.util.Scanner;

public class Main {
    static int n ;
    static String [] s ;
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        n = input.nextInt()  ;
        s = new String [4] ;

        for(int i=0; i<4; i++){
            s[i] = input.next() ;
        }
        double acc , ans ;
        for(int j=0; j<4; j++) {
            ans = acc= 0 ;
            for (int i = 0; i < s[j].length(); i++) {
                if(s[j].charAt(i)=='>'){
                    ans += 0.5 ;
                    acc = 4.5 ;
                    continue;
                }
                if(s[j].charAt(i)=='.' && acc >0){
                    if(acc>=0.5) {
                        ans += 0.5;
                        acc -= 0.5;
                    }else{
                        ans += acc + (1- acc*2) ;
                        acc = 0 ;
                    }
                    continue;
                }
                if(s[j].charAt(i)=='.' && acc <= 0){
                    ans += 1 ;
                    continue;
                }
                if(s[j].charAt(i)=='w' && acc >0){
                    if(acc>=1) {
                        ans += 1;
                        acc--;
                    }else{
                        ans += acc + (1-acc)*2 ;
                        acc = 0 ;
                    }
                    continue;
                }
                if(s[j].charAt(i)=='w' && acc <=0){
                    ans += 2 ;
                    continue;
                }

                if(s[j].charAt(i)=='s'){
                    ans ++ ;
                    acc-- ;
                    if(acc>0){
                        if(acc>=0.5) {
                            ans += 0.5;
                            acc -= 0.5;
                        }else{
                            ans += acc + (1- acc*2) ;
                            acc = 0 ;
                        }
                    }else{
                        ans += 1 ;
                    }
                }

                if(s[j].charAt(i)=='m'){
                    ans += 2 ;
                    acc -= 2 ;
                    if(acc>0){
                        if(acc>=0.5) {
                            ans += 0.5;
                            acc -= 0.5;
                        }else{
                            ans += acc + (1- acc*2) ;
                            acc = 0 ;
                        }
                    }else{
                        ans += 1 ;
                    }
                }
            }
            System.out.printf("%.1f ",ans);
           
        }
    }
}

F题-大数据分析

 思路:签到题,注意是求总和,不是求第30天。

public class Main {
    static int mod = 1000000007 ;
    public static void main(String[] args) {
        long ans = 1, sum = 1 ;
        for(int i=2; i<=30; i++){
            ans = ans * (ans + 5) % mod ;
            sum = (sum + ans) % mod ;
        }
        System.out.println(sum);
    }
}

G题-数学math

思路;这题乍一看简单,仔细一看,发现数据太大了,正常的写法AC不了,爆内存了。我的爆的代码仅供参考。

import java.util.Scanner;

public class Main {
    static int mod = 1000000007 ;
    static int k, a, b ;
    static int l, r ;
    static long [][] c  ;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
         k = input.nextInt() ;
         a = input.nextInt() ;
         b = input.nextInt() ;
         l = input.nextInt() ;
         r = input.nextInt() ;
         c = new long[10000][10000] ;
         long ans = 0 ;

         init();
        for(long i=l; i<=r; i++){
            ans = (ans%mod + c[f(i)][k]%mod) %mod ;
        }
        System.out.println(ans);
    }

    public static void init() {
        for (int i = 0; i < 10000; i++)
            for (int j = 0; j <= i; j++)
                if (j == 0) c[i][j] = 1;
                else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
    }
    private static int f(long i){
        if(i==1 || i==2){
            return 1 ;
        }
        return (a * f(i-1)%mod + b * f(i-2)%mod)%mod ;
    }
}

 

H题-最大化

思路:判断是否联通,我用的并查集判断你是否联通的,如果不连通,就一定是无穷大,输出-1,如果联通, 我用的bfs去搜索,搜索的轮数num,用(num-1)*D就是答案。AC代码如下:

import java.util.*;

public class Main {
    static int [] fa ;
    static List<List<Integer>> list ;
    static boolean [] vis ;
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        int n = input.nextInt() ;
        int D = input.nextInt() ;
        fa = new int [n+1] ;
        vis = new boolean[n+1] ;
        int [] inDegree = new int [n+1] ;
        list = new ArrayList<>() ;

        for(int i=0; i<=n; i++){
            list.add(new ArrayList<>()) ;
        }

        int [][] edge = new int [n+1][n+1] ;

        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                edge[i][j] = input.nextInt() ;
                if(edge[i][j]==1){ //构建邻接表
                    list.get(i).add(j) ;
                    list.get(j).add(i) ;
                    inDegree[i] ++ ;
                    inDegree[j] ++ ;
                }
            }
        }
        for(int i=1; i<=n; i++){
            fa[i] = i ;
        }

        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                if(edge[i][j]==1){
                    union(i,j) ;
                }
            }
        }
        int ans = 0 ;
        for(int i=1; i<=n; i++){
            if(i==find(i)){
                ans ++ ;
            }
        }

        int min = inDegree[1] ;
        int index = 1;
        for(int i=2; i<=n; i++){
            if(min>inDegree[i]){
                min = inDegree[i] ;
                index = i ;
            }
        }

        Queue<Integer> queue = new LinkedList<>() ;
        int num = 0;
        if(ans==1){ //联通
            //从入度最少的开始广度优先遍历
            queue.add(index) ;
            vis[index] = true ;
            while(!queue.isEmpty()){
                num ++ ;
                int size = queue.size() ;
                for(int i=0; i<size; i++){
                    int x = queue.poll() ;
                    for(int y : list.get(x)){
                        if(!vis[y]) {
                            queue.add(y);
                            vis[y] = true ;
                        }
                    }
                }
            }
            System.out.println((num-1)*D);
        }else{
            System.out.println(-1);
        }

    }
    private static int find(int x){
        if(x!=fa[x]){
            fa[x] = find(fa[x]) ;
        }
        return fa[x] ;
    }
    private static void union(int x, int y){
        int root1 = find(x) ;
        int root2 = find(y) ;
        if(root1==root2){
            return ;
        }
        fa[root1] = root2 ;
    }
}

I题-小x的好路-road

思路:题目不难,但是题目描述的晦涩难懂,有种外文谷歌翻译的感觉,哈哈,这题是贪心策略,就是将每个顶点的所有边按升序排序,每次选择两个边权的最大值累加,就是答案,不过这个题对Java选手并不友好,我们使用常用的Scanner类或者BufferedReader读取都判超时,我都想骂娘了,不说了,看一下AC代码吧。这个用时0.6s。

import java.io.*;
import java.util.*;

public class Main {
    static List<Integer>[] g ;
    public static void main(String[] args) throws IOException {
        StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        in.nextToken() ;
        int n = (int) in.nval ;
        int m = n * (n-1) / 2 ;
        g = new List[n+1] ;

        for(int i=0; i<=n; i++){
            g[i] = new ArrayList<>() ;
        }

        for(int i=1; i<=m; i++){
            in.nextToken() ;
            int u = (int)in.nval ;
            in.nextToken() ;
            int v = (int)in.nval ;
            in.nextToken() ;
            int w = (int)in.nval ;
            g[u].add(w) ;
            g[v].add(w) ;
    }

        long ans = 0 ;
        for(int i=1; i<=n; i++){
            Collections.sort(g[i]);
            for(int j=1; j<g[i].size(); j+=2){
                ans += g[i].get(j) ;
            }
        }
        out.println(ans);
        out.flush();
    }
}

 我们看一下超时代码,这个用时1.9s,判定超时,大部分的时间都用在处理输入输出,你敢信。

import java.util.*;

public class Main {
    static Vector<Integer>[] g ;
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in) ;
        int n = input.nextInt() ;
        int m = n * (n-1) / 2 ;
        g = new Vector[n+1] ;

        for(int i=0; i<=n; i++){
            g[i] = new Vector<>() ;
        }

        for(int i=1; i<=m; i++){
            int u = input.nextInt() ;
            int v = input.nextInt() ;
            int w = input.nextInt() ;

            g[u].add(w) ;
            g[v].add(w) ;
        }
        long ans = 0 ;
        for(int i=1; i<=n; i++){
            Collections.sort(g[i]);
            for(int j=1; j<g[i].size(); j+=2){
                ans += g[i].get(j) ;
            }
        }
        System.out.println(ans);
    }
}

我们再看一下这个,用时1.5s,BufferedReader比Scanner类快一点,但是还是超时。

import java.io.*;
import java.util.*;

public class Main {
    static List<Integer>[] g ;
    public static void main(String[] args) throws IOException {
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(input.readLine());
        int m = n * (n-1) / 2 ;
        g = new List[n+1] ;

        for(int i=0; i<=n; i++){
            g[i] = new ArrayList<>() ;
        }

        for(int i=1; i<=m; i++){
            String [] a = input.readLine().split("[ ]") ;
            int u = Integer.parseInt(a[0]) ;
            int v = Integer.parseInt(a[1]) ;
            int w = Integer.parseInt(a[2]) ;

            g[u].add(w) ;
            g[v].add(w) ;
    }
        input.close();
        long ans = 0 ;
        for(int i=1; i<=n; i++){
            Collections.sort(g[i]);
            for(int j=1; j<g[i].size(); j+=2){
                ans += g[i].get(j) ;
            }
        }
        System.out.println(ans);
    }
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值