2014 年赛题

1、

标题:猜字母

    把abcd...s共19个字母组成的序列重复拼接106次,得到长度为2014的串。

    接下来删除第1个字母(即开头的字母a),以及第3个,第5个等所有奇数位置的字母。

    得到的新串再进行删除奇数位置字母的动作。如此下去,最后只剩下一个字母,请写出该字母。

答案是一个小写字母,请通过浏览器提交答案。不要填写任何多余的内容。*/

tip:参考以为大佬的写法https://www.cnblogs.com/upstart/p/6677265.html 很妙了

这个题首先可以数学方法分析
一列连续正整数无限去除奇数位,最后留下来的肯定是2的N次方中最大的那个,
口算就是1024位 ,
1024除以19取余是17,
17位的字母就是q

 

编程的话也可以,就是用一个StringBuffer把“abcdefghigklmnopqrs”存106次,然后删除

这个有个比较有趣的地方是,由于delect方法的问题,每次删除掉第i个之后,i后面的都会整体前移一位,所以删除第i个其实是删除了所有奇数位的元素。

public class Main {
    public static void main(String[] args) {
        StringBuffer base = new StringBuffer();
        for (int i = 0; i < 106; i++) {
            base.append("abcdefghigklmnopqrs");
        }
        while (base.length() > 1) {
            for (int i = 0; i < base.length(); i++)
                base.deleteCharAt(i);
        }
        System.out.println(base);
    }
}

2、

标题:扑克序列

    A A 2 2 3 3 4 4, 一共4对扑克牌。请你把它们排成一行。
    要求:两个A中间有1张牌,两个2之间有2张牌,两个3之间有3张牌,两个4之间有4张牌。

    请填写出所有符合要求的排列中,字典序最小的那个。

例如:22AA3344 比 A2A23344 字典序小。当然,它们都不是满足要求的答案。

 

public class _07扑克排序 {
  public static void main(String[] args) {
    char[] a = {'A', 'A', '2', '2', '3', '3', '4', '4'};
    f(a, 0);
    for (String s : set
        ) {
      System.out.println(s);
    }
  }

  static Set<String> set = new HashSet<String>();

  private static void f(char[] a, int k) {
    if (k == a.length) {
      String s = new String(a);
      if (check(s))
        //System.out.println(s);
        set.add(s);
    }
    for (int i = k; i < a.length; i++) {
      char t = a[k];
      a[k] = a[i];
      a[i] = t;

      f(a, k + 1);

      t = a[k];
      a[k] = a[i];
      a[i] = t;
    }
  }

  private static boolean check(String s) {
    if (s.lastIndexOf('A') - s.indexOf('A') == 2 &&
        s.lastIndexOf('2') - s.indexOf('2') == 3 &&
        s.lastIndexOf('3') - s.indexOf('3') == 4 &&
        s.lastIndexOf('4') - s.indexOf('4') == 5)
      return true;
    return false;
  }
}

标题:分糖果

    有n个小朋友围坐成一圈。老师给每个小朋友随机发偶数个糖果,然后进行下面的游戏:

    每个小朋友都把自己的糖果分一半给左手边的孩子。

    一轮分糖后,拥有奇数颗糖的孩子由老师补给1个糖果,从而变成偶数。

    反复进行这个游戏,直到所有小朋友的糖果数都相同为止。

    你的任务是预测在已知的初始糖果情形下,老师一共需要补发多少个糖果。

【格式要求】

    程序首先读入一个整数N(2<N<100),表示小朋友的人数。
    接着是一行用空格分开的N个偶数(每个偶数不大于1000,不小于2)
    要求程序输出一个整数,表示老师需要补发的糖果数。

例如:输入
3
2 2 4
程序应该输出:
4

我代码不对????代码不对的原因是不知道圆形位置的特殊性,要注意收尾相连啊

import java.util.Scanner;

class Kruskal{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; ++i) {
            a[i] = sc.nextInt();
        }
        int ans = 0;
        while (check(a)==false){
            for(int i=0;i<n-1;i++){
                a[i]-=a[i]/2;
                a[i] += a[i+1]/2;
                if((a[i] &1)==1){
                    ans++;
                    a[i] ++;
                }
            }
        }
        System.out.println(ans);

    }
    static boolean check(int [] a){
        for(int i=0;i<a.length;i++){
            if(a[i]==a[0]){

            }else {
                return false;
            }
        }
        return true;
    }
}
public class _08分糖果 {
  public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = sc.nextInt();
    int[] a = new int[n];
    for (int i = 0; i < n; ++i) {
      a[i] = sc.nextInt();
    }
    int ans = 0;
    while (true) {
      int t = a[0];
      for (int i = 0; i <= n - 2; ++i) {
        a[i] -= a[i] / 2;
        a[i] += a[i + 1] / 2;
        if ((a[i] & 1) == 1) {
          ans++;
          a[i]++;
        }
      }
      a[n - 1] -= a[n - 1] / 2;
      a[n - 1] += t / 2;
      if ((a[n - 1] & 1) == 1) {
        ans++;
        a[n - 1]++;
      }
      if (check(a, n)) {
        System.out.printf("%d\n", ans);
        return;
      }
    }
  }

  private static boolean check(int[] a, int n) {
    int t = a[0];
    for (int i = 1; i < n; ++i) {
      if (a[i] != t) return false;
    }
    return true;
  }
}

4、

标题:地宫取宝

    X 国王有一个地宫宝库。是 n x m 个格子的矩阵。每个格子放一件宝贝。每个宝贝贴着价值标签。

    地宫的入口在左上角,出口在右下角。

    小明被带到地宫的入口,国王要求他只能向右或向下行走。

    走过某个格子时,如果那个格子中的宝贝价值比小明手中任意宝贝价值都大,小明就可以拿起它(当然,也可以不拿)。

    当小明走到出口时,如果他手中的宝贝恰好是k件,则这些宝贝就可以送给小明。

    请你帮小明算一算,在给定的局面下,他有多少种不同的行动方案能获得这k件宝贝。

【数据格式】

    输入一行3个整数,用空格分开:n m k (1<=n,m<=50, 1<=k<=12)

    接下来有 n 行数据,每行有 m 个整数 Ci (0<=Ci<=12)代表这个格子上的宝物的价值

    要求输出一个整数,表示正好取k个宝贝的行动方案数。该数字可能很大,输出它对 1000000007 取模的结果。

例如,输入:
2 2 2
1 2
2 1
程序应该输出:
2

再例如,输入:
2 3 2
1 2 3
2 1 5
程序应该输出:
14

这个代码,,我一直越界,,不知道为啥哎,,,,!!!发现原因,防御性编程放到刚开头!!

import java.util.Scanner;

class Main{
    private static final int MOD = 1000000007;
    static int[][] data;
    private static int n;
    private static int m;
    private static int k;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        k = sc.nextInt();
        data = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                data[i][j] = sc.nextInt();
            }
        }
        long ans = dfs(0,0,-1,0);
        System.out.println(ans);
    }
    static long dfs(int x,int y, int max ,int cnt){
        int cur = data[x][y];
        int ans = 0;
        if(x==n-1 && y==m-1){
            if(cnt ==k) return 1;
            return ans;
        }
        if(cur>max){
            ans+=dfs(x,y+1,cur,cnt+1);
            ans+=dfs(x,y+1,cur,cnt+1);
        }
        ans+=dfs(x,y+1,max,cnt);
        ans+= dfs(x+1,y,max,cnt);
        return ans%MOD;
    }
}

这里是正确代码,是记忆性递归,这里开的空间也不是很大,所以不需要转成动归,资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 2000ms,怎么算这个呢?  512*512*14*14*8就是字节数,/1024/1024就是多少M,

 这个,,,算出来是392哎,,,好像还真过不了,,,,过后改成动归把

import java.util.Scanner;

class test6{
    private static final int MOD = 1000000007;
    static int[][] data;
    private static int n;
    private static int m;
    private static int k;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();
        k = sc.nextInt();
        data = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                data[i][j] = sc.nextInt();
            }
        }
        for(int i =0;i<51;i++){
            for(int j =0;j<51;j++){
                for (int l =0;l<14;l++){
                    for(int o = 0;o<14;o++){
                        cache[i][j][l][o] = -1;
                    }
                }
            }
        }
        long ans = dfs(0,0,-1,0);
        System.out.println(ans);
    }
    //改一下记忆性搜索啦,dfs有几位参数,我们就声明几位的数组
    static long[][][][] cache = new long[51][51][14][14];
    static long dfs(int x,int y, int max ,int cnt){

        if(x==n ||y==m ||cnt>k){ //这里有下标越界的可能,防御性的编程要放到刚开头去
            return 0;
        }
        if(cache[x][y][max+1][cnt]!=-1){
            return cache[x][y][max+1][cnt];
        }

        int cur = data[x][y];
        int ans = 0;
        if(x ==n-1 && y==m-1){
            if(cnt==k ||(cnt==k-1 && cur>max)){
                return 1;
            }
        }

        if(cur>max){
            ans+=dfs(x,y+1,cur,cnt+1);
            ans+=dfs(x+1,y,cur,cnt+1);
        }
        ans+=dfs(x,y+1,max,cnt);
        ans+= dfs(x+1,y,max,cnt);

        cache[x][y][max+1][cnt] = ans%MOD;
        return ans;
    }
}

5、

标题:矩阵翻硬币

    小明先把硬币摆成了一个 n 行 m 列的矩阵。

    随后,小明对每一个硬币分别进行一次 Q 操作。

    对第x行第y列的硬币进行 Q 操作的定义:将所有第 i*x 行,第 j*y 列的硬币进行翻转。

    其中i和j为任意使操作可行的正整数,行号和列号都是从1开始。  //这句话的意思是x和y都不为0

    当小明对所有硬币都进行了一次 Q 操作后,他发现了一个奇迹——所有硬币均为正面朝上。

    小明想知道最开始有多少枚硬币是反面朝上的。于是,他向他的好朋友小M寻求帮助。

    聪明的小M告诉小明,只需要对所有硬币再进行一次Q操作,即可恢复到最开始的状态。然而小明很懒,不愿意照做。于是小明希望你给出他更好的方法。帮他计算出答案。

【数据格式】
    输入数据包含一行,两个正整数 n m,含义见题目描述。
    输出一个正整数,表示最开始有多少枚硬币是反面朝上的。

【样例输入】
2 3

【样例输出】
1

【数据规模】
对于10%的数据,n、m <= 10^3;
对于20%的数据,n、m <= 10^7;
对于40%的数据,n、m <= 10^15;
对于100%的数据,n、m <= 10^1000(10的1000次方)。    //这个输出真的是非常那个大了,常规模拟肯定是不行的

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 2000ms

tip:比如考虑(x,y)这个点的一个比会被翻多少下,比如x是三,那么x为1时他会动,x为三时他会动,即x为3的所有因子时他都会动,那么y动的时候就是y的真因子的个数了,那么这个点一共会被翻动次数为x的真因子成y的真因子的个数

真因子个数??9就是1 3 9    9是奇数那么他的真因子的个数就是奇数,,9的特点就是9是平方数

       10 就是1 2 5 10

如果两个因子的乘积为偶数,那么翻转不影响他的正反面,乘积为奇数,才会影响正反,,

那么,奇数成奇数为奇数,,奇数成偶数为偶数,偶数成偶数为偶数 

那么,这个题推出,求n中有多少个平方数,m中有多少个个平方数

那么找平方数,,枚举,10的1000次方,,枚举会超时,这儿其实有公式,,有根号n个恩,可以举个例子试试

所以答案为 sqrt(n)×aqrt(m) 

大数开平方??这个问题,参照了一篇非常牛逼的博客https://blog.csdn.net/wr132/article/details/43772189#commentBox

首先,让我们明确一下思路,到底如何实现乘法和开方,对于大数的存储,我们使用string,因为它的长度比较容易控制

大数乘法:

乘法:其实有很多速度快而且更巧妙的大数乘法,但是在蓝桥杯,我们只要使用模拟手算法应该是问过,虽说是模拟,但也有一些我们常用但不太了解的规律,我们在手算乘法的时候,需要进行移位和进位,这两个操作我们会通过两步完成

1.移位:对于两个数a=12,b=25,在相乘的时候我们让每一位数分别相乘,即a[0]*b[0]=2 , a[0]*b[1]=5 , a[1]*b[0]=4 , a[1]*b[1]=10,那么规律就是,对于两个数a[i] , b[j],所有i+j相同的数都要加到一起,所以我们要把5+4=9合并为一个数,也就是说,将每一位数相乘之后,我们实际得到了2,9,10三个没有进位的数

2.进位:通过上面的操作,我们的2,9,10三个没有进位的数,下面就要进行进位,因为我们是把高位相乘得到的数放在前面,地位相乘得到的数放在后面,所以这三个数排列自然也是高位在前,地位在后,所以要从右向左进位,进位的方法就是a[i]=a[i+1]/10 , a[i+1]=a[i+1]%10,如果放到这三个数上面,就是,9+10/10=10,然后10%10=0,这三个数变成2,10,0,再一次就是2+10/10=3,10%10=0,三个数变为3,0,0,而这正是我们要求的结果,在实际操作中,我们习惯于将数倒着存放,即将数存为10,9,2,这是为了进位方便,因为如果正序的话如果最高位发生进位我们就要将每一个数向后移动一位从而挪出一个空位,想想都麻烦,倒序的话因为是向后进位,想怎么进就怎么进

大数开方

这个方法的前提:假如一个数有偶数位n,那么这个数的方根有n/2位;如果n为奇数,那么方根为(n+1)/2位。

然后,让我们实际看一个例子,我们假设这个数就是1200

1.很明显,它有4位,所以它的方根有2位,然后,我们通过下面的方法来枚举出它的整数根

 00*00=0<1200

    10*10=100<1200

    20*20=400<1200

    30*30=900<1200

      40*40=1600>1200

所以,这个根的十位就是3,然后,再枚举个位

                                                    31*31=961<1200

32*32=1024<1200

33*33=1089<1200

34*34=1156<1200

35*35=1225>1200

所以,这个根就是34,因为平方增长的速度还是比较快的,所以速度没有太大问题,这里有一个地方需要处理一下,如果一个数很长,那么它的方根的位数也比较长,在枚举高位的时候,我们没有必要把后面的0都加上,因为那样会影响速度,其实0的个数完全可以算出来,然后将0的个数一起送入比较函数比较即可,这样可以提高速度

比较:上面我们说过,比较函数接受的两个数只有一个是完整的数,另外一个实际上是高几位的平方和0的个数,但处理方式差不多,都是先比较位数,位数大数就大,位数一样就逐位比较,只要别忘了比较那一堆0就好了,最后其实不用把情况分的太清楚,只要返回0,1就行,因为只有当一个数大于n的时候才对我们有意义

另外:Bigdecimal和biginteger的 区别 BigDecimal的实现利用到了BigInteger, 所不同的是BigDecimal加入了小数位的概念,比如BigDecimal d = new BigDecimal(new BigInteger(ib),5);5表示的是5个小数位。BigDecimal可以用来做超大的浮点数的运算,比如+-*/的运算,其中除法运算是最复杂的,因为商的位数还有除不断的情况下末位小数点的处理都是需要考虑的。

public BigDecimal multiply(BigDecimal multiplicand) 大数想乘

这个题的代码:

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Scanner;

public class Test48 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s1 = sc.next();
        String s2 = sc.next();
        System.out.println(sqrt(s1).multiply(sqrt(s2)));

    }
    static BigInteger sqrt(String s){
        int length = s.length();
        int len = 0;
        if(length%2==0){
            len = length/2;
        }else {
            len = len/2+1;
        }
        char[] sar=new char[len];
        Arrays.fill(sar,'0');
        BigInteger target =  new BigInteger(s);   //转化字符串s为大数
        for(int pos =0;pos<len;pos++){
            for(char c = '1';c<'9';c++){
                sar[pos] = c;//在pos这个位置上试着填入1-9
                BigInteger pow = new BigInteger(String.valueOf(sar)).pow(2);
                if(pow.compareTo(target)==1){//试探数的平方更大
                    sar[pos] -=1;
                    break;
                }
            }
        }
        return new BigInteger(String.valueOf(sar));
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值