EL算法比赛第一轮第三次--contest167

说在前面:自己第一次写博客,嘿嘿,有点小兴奋

结果总结:队伍由于超时等多种原因,导致成绩并不理想,六道题,只做对了两道。。。
个人总结:遇到复杂的问题有想法但是苦于不知道如何去实现,还是敲代码的技巧太过生疏,奥里给!

C - Skill Up

在这里插入图片描述
在这里插入图片描述
基本题意:找出最少钱,能使他的每一列的和均达到X的值
不难想出,这本质上就是一个排列组合问题,然后分情况模拟就OK。
但关键就是如何实现?


import java.util.*;
public class Main{
 public static void main(String[] args)
 {
 	Scanner in=new Scanner(System.in);
	int n=in.nextInt(),m=in.nextInt(),x=in.nextInt();
  	int[][] arr=new int[n][m+1];
 	 for(int i=0;i<n;i++)
  	{
  	    for(int j=0;j<=m;j++)
  	    {
  	    	arr[i][j]=in.nextInt();
  	    }
  	}
  	int ans=1000000007;  //32位的最大质数
  	for(int i=1;i<(1<<n);i++)  //二项式定理,你懂的
  	{
  	    boolean f=true;
  	    int[] ar=new int[m];
  	    int sum=0;
  	    for(int j=0;j<n;j++)
  	    {
  	    //找到挑的位置 难点!!
  	    	if((1&(i>>j))==1)
  	    	{
  	    	    sum+=arr[j][0];
  	    	    for(int k=1;k<=m;k++)
  	    	    {
  	    	    //建立k-1与k 列的映射关系,妙!
  	    	    	ar[k-1]+=arr[j][k]; //美妙的计算每一列的总和
  	    	    }
  	    	}
  	     }
  	     for(int j=0;j<m;j++)
  	     {
  	     	if(ar[j]<x)
  	     	    f=false;;
  	     }
  	     if(f)
  	     	ans=Math.min(ans,sum);
  	    if(ans==1000000007)
            {
                 System.out.println(-1);
            }
            else
            {
                 System.out.println(ans);
            }
      }
}

太爱这道题的 位运算!!
也是跟队员才了解学会到 这个C(m,n)的实现,想象:
000–111 这三个书架,你选择相当于放了1本书即为1 第二次位运算则是去判断这个书架到底有没有书。

还有 2^n 这个排列组合数学公式:体现在第一哥位运算

D - Teleporter

在这里插入图片描述
在这里插入图片描述
这道题大概意思就是有个闲着没事的时光老头穿梭时空,每到一个时空,就会给她一个神奇的数字,然后他TP到数字所指定的位置,一直K次
关键很简单,就是找出循环(还要找出前后点

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

public class Main {	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);

		int n = sc.nextInt();	//N座城镇
		long k = sc.nextLong();	//穿越K次

		int[] array = new int[n];
		//一步步读取数据,城镇轨迹
		for(int i = 0 ; i < n; i++) {
			array[i] = sc.nextInt();
		}
		//ord作为一个对照作用,来确定保存循环的位置!!
		int[] ord = new int[n+1];
		for(int i = 0; i < n + 1; i++) {
			ord[i] = -1;
		}

		int now = 1;
		//建立list用来保存特定点,循环前点与第一次循环圈
		List<Integer> list = new ArrayList<>();
		
	//个人感觉代码的关键部分。原来初始化-1在这里是为了当出现过那么就已经更新,而且,还获得了循环开始点ord[now]的位置。也为下一步求周期,size之差奠定基础

		while(ord[now] == -1) {
			ord[now] = list.size();
			list.add(now);
			now = array[now -1];//时时更新下一步要到哪里

		}

		int circle = list.size() - ord[now]; //周期
		int length_begin = ord[now];
	//判定就很简单了,
		if(k < length_begin) {
			System.out.println(list.get((int)k));
		}else {
			k -= length_begin;//这一步是要先减的不能直接除因为可能前点大于circle 
			k %= circle;
			System.out.println(list.get((int)k+length_begin));
		}
	}
}

E - Colorful Blocks

在这里插入图片描述
在这里插入图片描述
意思:有N个块排在一行,M种颜色,求当他们相邻快颜色最多有K个不同时,求总共给多少种可能。
这个题还不是很懂,但是和排列组合有关。。。淦,写到这里突然懂了算法。
loop k1=0 to k:
ans+=c(n-1,k1)m(m-1)^(n-1-k1)
思路:n个数有n-1对,假设有k1个可以相同,那么第一个放颜色为m个,剩余就是(m-1)^(n-1-k1)个,但是由于k1所在位置不确定,因此再C挑选位置

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;

public final class Main {

    private static final int MOD = 998244353;

    static class Solver {
        long[] factorial;
        long[] facInverse;
        long[] inverse;

        void solve(int n, int m, int k) {
            init(n);
            int sum = 0;
            for (int i = 0; i <= k; i++) {
                final long edge = ncr(n - 1, i);
                sum = (int) ((sum + (edge * (m * modpow(m - 1, n - 1 - i) % MOD)) % MOD) % MOD);
            }
            System.out.println(sum);
        }

        void init(int n) {
            final int MAX = n + 2;
            factorial = new long[MAX];
            facInverse = new long[MAX];
            inverse = new long[MAX];
            factorial[0] = factorial[1] = 1;
            facInverse[0] = facInverse[1] = 1;
            inverse[1] = 1;
            for (int i = 2; i < MAX; i++) {
                factorial[i] = factorial[i - 1] * i % MOD;
                final long inv = inverse[i] = MOD - inverse[MOD % i] * (MOD / i) % MOD;
                facInverse[i] = facInverse[i - 1] * inv % MOD;
            }
        }

        long ncr(int n, int r) {
            if (n < r) { return 0; }
            if (n < 0 || r < 0) { return 0; }
            return factorial[n] * (facInverse[r] * facInverse[n - r] % MOD) % MOD;
        }

        long modpow(long a, long n) {
            long res = 1;
            while (n > 0) {
                if (n % 2 == 1) {
                    res = res * a % MOD;
                }
                a = a * a % MOD;
                n /= 2;
            }
            return res;
        }
    }

    public static void main(String[] args) {
        final Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        final int n = in.nextInt();
        final int m = in.nextInt();
        final int k = in.nextInt();
        in.nextLine();
        new Solver().solve(n, m, k);
    }
}

F - Bracket Sequencing

在这里插入图片描述
在这里插入图片描述
这个题,想法就是,任意排列之后,是否可以得到有效括号序列
自己的想法是全排列之后再一个个判断合法括号。。。当然会超时

import java.util.*;

public class Main {
	public static void main (String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		PriorityQueue<Paren> queue = new PriorityQueue<>();
		for (int i = 0; i < n; i++) {
		    queue.add(new Paren(sc.next().toCharArray()));
		}
		long current = 0;
		while (queue.size() > 0) {
		    Paren p = queue.poll();
		    if (current + p.min1 < 0) {
		        System.out.println("No");
		        return;
		    }
		    current += p.result;
		}
		if (current == 0) {
		    System.out.println("Yes");
		} else {
		    System.out.println("No");
		}
	}
	
	static class Paren implements Comparable<Paren> {
	    int result;
	    int min1;
	    int min2;
	    
	    public Paren(char[] arr) {
	        min1 = 0;
	        result = 0;
	        for (char c : arr) {
	            if (c == '(') {
	                result++;
	            } else {
	                result--;
	            }
	            min1 = Math.min(min1, result);
	        }
	        min2 = min1 - result;
	    }
	    
	    public int compareTo(Paren another) {
	        if (result > 0 && another.result > 0) {
	            return another.min1 - min1;
	        } else if (result > 0 && another.result <= 0) {
	            return -1;
	        } else if (result <= 0 && another.result > 0) {
	            return 1;
	        } else {
	            return min2 - another.min2;
	        }
	    }
	}
}

我是一名小蓝鲸,这也是我写的第一篇博客
刚学不到两个月,F对我来说现阶段有些困难。。但也希望对看到的人有帮助,谢谢!
希望大家给我点一个赞,(●’◡’●)

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值