2013A组题一:

题干
/**

  • 2013A组题一:

  • 世纪末的星期:

  • 曾有邪教称1999年12月31日是世界末日
  • 还有人称今后的某个世纪末的12月31日,如果是星期一则会。。。
  • 有趣的是,任何一个世纪末的年份的12月31日都不可能是星期一
  • 于是,“谣言制造商”有修改为星期日。。。

  • 1999年的12月31日是星期五,请问:
  • 未来哪一个离我们最近的一个世纪末年(即xx99年)的12月31日正好是星期五(即星期日)?

  • 请回答该年份(只写这个4位整数,不要写12月31日等多余信息

*/

public class A_A_2013 {
 public static void main(String[] args) {
  //创建Calendar对象
  Calendar ca = Calendar.getInstance();
  for(int year=1999; ;year+=100) {
   ca.set(Calendar.YEAR , year);//设置年份为year,以100年速度递增
   ca.set(Calendar.MONTH  , 11); //12月
   ca.set(Calendar.DAY_OF_MONTH , 31);
   System.out.println(year+" "+ca.get(Calendar.DAY_OF_WEEK));
   if(ca.get(Calendar.DAY_OF_WEEK) == 1) { //1为Sunday
    System.out.println(year);
    break;
   }
  }
 }
}

2013A组题二:

题干
/**

  • 2013A组题二:

  • 振兴中华:

  • 小明参加了学校的趣味运动会,其中一个项目是跳格子
  • 地上画着一些格子,每个格子里写着一个字,如下所示:

  • 从我做起振
  • 我做起振兴
  • 做起振兴中
  • 起振兴中华

  • 比赛时,先站在左上角的 “从” 字的格子里,可以横向或纵向跳到相邻的格子里
  • 但不能跳到对角的格子或其他位置,一直要跳到 “华” 字结束
  • 请你帮助小明算一算他一共有多少种可能的跳跃路线?

  • 答案是一个整数,请直接提交该数字

*/

public class A_B_2013 {
 /**
  * 12345
  * 23456
  * 34567
  * 45678
  * 
  * 12345678
  */
 /**
  * 适合使用递归方法
  * 坐标表示:
  * (0,0)————(0,4)
  *   |
  *   |
  *   |
  *  (3,0)————(3,4)
  * 只能向右或向下走
  * 到达边界即可结束进行计数
  * dfs深搜
  */
 public static void main(String[] args) {
  int ans = f(0 , 0);//起始坐标(0,0)
  System.out.println(ans);
 }
 public static int f(int i,int j) {
  if(i==3||j==4) {//到达边界情况
   return 1;
  }
  return f(i+1 , j)+f(i , j+1);//将两种走法的路线数相加
 }
}

2013A组题三:

题干
/**

  • 2013A组题三:

  • 梅森素数:

  • 如果一个数字的所有真因子之和等于其本身,则称它为“完全数”或“完美数”
  • 例如:6 = 1 + 2 + 3
  • 28 = 1 + 2 + 4 +7 +14

  • 早在公元前300多年,欧几里得就给出了判定完全数的定理:
  • 若2^n-1 是素数,则2^(n-1) * (2^n-1) 是完全数
  • 其中 ^ 表示乘方运算,乘方的优先级比四则运算高
  • 但人们很快发现,当n很大时,判定一个大数是否为素数到今天也依然是个难题
  • 因为发过数学家梅森的猜想,我们习惯上把形如: 2^n-1的素数称为梅森素数
  • 截止到2013年2月,一共找到了48个梅森素数,新进找到的素数太大,以至于难于用一半的编程思想
  • 窥其全貌,所以我们把任务难度降低:

  • 1963年,美国伊利诺伊大学为了纪念他们找到的第23个梅森素数 n = 11213 , 在每个
  • 寄出的信封上都印上了 “2^11213-1 是素数” 的字样。

  • 2^11213 - 1这个数字已经很大了(有3000多位),请你编程求出这个素数的十进制表示的最后100位


  • 该数是一个长度为100的数字串

*/

//考点:BigInteger
public class A_C_2013 {
 public static void main(String[] args) {
  //BigInteger b 计算2^11213,然后再用封装的方法substract做减法运算
  BigInteger b = BigInteger.valueOf (2).pow(11213).subtract(BigInteger.ONE);
  String s = b.toString();
  int length = s.length();
  System.out.println(length);
  //截取字符串,填入的是下标
  String ans = s.substring(length-100);//从该位开始复制
  System.out.println(ans+"\n"+ans.length());
 }
}

2013A组题四:

题干
/**

  • 2013A组题四:

  • 颠倒的价牌:

  • 小李的店里专卖其他店中下架的样品电视机,可称为样品电视专卖店
  • 其标价都是四位数
  • 小李为了标价清晰、方便,使用了预制的类似数码管的标签价
  • 只要用颜色笔涂数字就可以了。这个价牌有个特点,有一些数字
  • 倒过来看也是合理的数字,如:1 2 5 6 8 9 0 都可以。这样一来,
  • 如果牌子倒挂了,有可能完全变成了另一个价格
  • 比如:1958 倒挂后就是 8561 差了几千元!
  • 当然,多数情况不能倒读,比如:1110,因为0不能作为开始数字。
  • 有一点,悲剧终于发生了,某个店员不小心把店里的某两个价格牌给
  • 挂倒了,并且两个价格牌的电视机都卖了出去,庆幸的是价格出入不大
  • 其中一个赔了两百多,另一个赚了八百多,综合起来,多赚了558元

  • 根据这些信息计算:赔钱的那个价牌正确的价格应是多少?


  • 答案是一个四位数整数

*/

public class A_D_2013 {
 public static void main(String[] args) {
  ArrayList<Price> a1 = new ArrayList<Price>();
  ArrayList<Price> a2 = new ArrayList<Price>();
  //枚举四位数,简单筛选
  for(int i=1000;i<10000;i++) {
   String s = i+"";
   if(s.contains("3")||s.contains("4")||s.contains("7")) continue;
   String re_s = reverse(s);//原串翻转
   int i1 = 0;//i1为颠倒价格
   try {
    i1 = Integer.parseInt(re_s.trim());
   }catch(NumberFormatException e) {
    System.out.println(e);
   }
   if(i1-i<-200 && i1-i>-300) {
    a1.add(new Price(i , i1-i));
   }
   if(i1-i>800 && i1-i<900) {
    a2.add(new Price(i , i1-i));
   }
  }
  //将其颠倒,和原价做差,将赔200多的放入一个集合,赚800多的放入另一个集合
  //遍历两个集合两两组合,差值为558就输出
  for(Price p1:a1) {//负值
   for(Price p2:a2) {
    if(p2.plus + p1.plus == 558) {
     System.out.println(p1.p+" "+p1.plus);
     System.out.println(p2.p+" "+p2.plus);
     System.out.println(p1.p);
    }
   }
  }
 }
private static String reverse(String s) {
  char[] ans = new char[s.length()];
  for(int i = s.length()-1 , j = 0 ; i > 0 ; i-- , j++) {
   char c = s.charAt(j);
   if(c == '6') {
    ans[j] = '9';
   }else if(c == '9') {
    ans[j] = '6';
   }else {
    ans[j] = c;
   }
  }
  return new String(ans);
 }
 private static class Price{
  int p; //原价
  int plus;  //差价=颠倒价-原价
  
  public Price(int p ,int plus) {
   this.p=p;
   this.plus=plus;
  }
 }
}

2013A组题五:

题干
/**

  • 2013A组题五:

  • 三部排序:

  • 一般的排序有许多的经典算法,如快速排序,希尔排序等等 但实际应用时,经常会或多或少有一些特殊的要求,我们没必要套用那些
  • 经典算法,可以根据实际情况建立更好的解法 比如:对一个整数组中的数字进行分类排序: 是的负数都靠左边,整数靠右边,0在中间。
  • 注意问题的特点是:负数区域和正数区域并不要求有序,可以利用这个特点通过一次 线性扫描就结束战斗。 以下程序实现了该目标

  • static void sort(int[] x) { int p = 0; int left = 0; int right = x.length-1;

  • while(p<=right){ if(x[p]<0){ int t =x[left]; x[left] = x[p]; x[p] = t;
  • left++; p++; }else if(x[p]>0){ int t = x[right]; x[right] = x[p]; x[p] = t;
  • right–; }else{ -----------------; //填写代码 } } }

*/

public class A_E_2013 {
 public static void main(String[] args) {
  int[] arr = new int[] {25,18,-2,0,16,-5,33,21,0,19,-16,25,-3,0};
  //测试特殊情况的用例
//  int[] arr1 = {};
//  int[] arr2 = {0,0,0,0,0,0,0};
//  int[] arr3 = {1,1,1,1,1,0};
  sort(arr);
  System.out.println(Arrays.toString(arr));
 }
 static void sort(int[] x) {
  int p = 0;
  int left = 0;
  int right = x.length - 1;
//用0为分界点,左边负数,右边正数
  while (p <= right) {//p指针在right左边时
   if (x[p] < 0) {
    //如果p的值小于0,交换
    int t = x[left];
    x[left] = x[p];
    x[p] = t;
    left++;//左边指针右移
    p++;//p指针右移,此时p指针为负数,左指针的左边也都是负数,左指针和p右移
   } else if (x[p] > 0) {//如果p的值大于0,交换
    int t = x[right];
    x[right] = x[p];
    x[p] = t;
    right--;//右指针左移,此时右指针位置为正数
   } else {//如果p指针的值等于0
//    //----------------------; // 填写代码
	p++;//正确答案,p指针右移,左指针指向0,即临界值,有负数与0交换
    //最终状态:左指针指向0,p指针在右指针右侧
   }
  }
 }
}

2013A组题六:

题干
/**

  • 2013年A組題六

  • 逆波兰表达式:

  • 正常的表达式称为中缀表达式,运算符在中间,主要是给人阅读的
  • 机器求解并不方便。例如:3+5*(2+6)-1
  • 而且,常常使用逆波兰表达式(前缀表达式表示),上面的算式则表示为:
  • 3 * 5 + 2 6 1
  • 不在需要括号,机器可以用递归的方法很方便的求解
  • 为了简便,我们说:

  • 1.只有 + - * 三种运算符
  • 2.每个运算数都是一个小于10的非负整数

  • 下面的程序对一个逆波兰表达串进行求值
  • 其返回值为一个数组,其中一个元素表示求值结果,第二个元素表示
  • 它已解析的字符数。



*/

public class A_F_2013 {
 //3+5*(2+6)-1
 // - + 3 * 5 + 2 6 1
   static int[] evaluate(String x) {
   if(x.length()==0) return new int[] {0,0};
  
   char c = x.charAt(0);  //获得第一个字符
   if(c>='0' && c<=9)    //这一个字符是0~9
   return new int[] {c-'0' , 1}; 
   int[] v1 = evaluate(x.substring(1));//第一个字符是运算符,截取后面的部分
  //?可以截取到上一步没有处理到的部分
  int[] v2 = evaluate(x.substring( 1+v1[1] ));  //填空位置
  
  int v = Integer.MAX_VALUE ;
  if(c == '+') v = v1[0] + v2[0];
  if(c == '*')  v = v1[0] *  v2[0];
  if(c == '-' )  v = v1[0] - v2[0];
  
  return new int[] {v , 1+v1[1]+v2[1] };
 }
}

2013A组题七

题干
/**

  • 2013A组题七:

  • 错误票据:

  • 某涉密单位下发了某种票据,并要在年终全部收回
  • 每张票据有唯一的ID号,全年所有票据的ID号是连接的,但ID的开始号码
  • 是随机选定的,因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成
  • 了某个ID断号,另外一个ID重号。你的任务是通过编程,找出断号的ID和重号的ID

  • 假设断号不可能发生在最大和最小号

  • 要求程序首先输入一个整数N(N<100)表示后面数据行数
  • 接着读入N行数据
  • 每行长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000)
  • 每个整数代表一个ID号

  • 要求输出1行,含两个整数m,n,用空格分隔
  • 其中,m表示断号ID ,n表示重号ID

  • 例如:
  • 用户输入:
  • 2
  • 5 6 8 11 9
  • 10 12 9

  • 程序输出:
  • 7 9





*/

public class A_G_2013 {
 public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  ArrayList<Integer> list = new ArrayList<Integer>();
  int N = sc.nextInt();
  sc.nextLine();  //吃掉数字后面的换行
  for(int i=0 ;i<N;i++) {
   String str = sc.nextLine();
   String[] res = str.split(" ");
   
   for(int j=0; j<res.length;j++) {
    try {
     list.add(Integer.parseInt(res[j].trim()));
    }catch(NumberFormatException e){
     System.out.println(e);
    }
   }
  }  
  sc.close();
  
  Collections.sort(list);//集合排列
  int m=0,n=0;
  for(int i=1;i<list.size();i++) {
   if(list.get(i)-list.get(i-1)==2)//后一项减去前一项==2,
    m = list.get(i)-1;
   
   if(list.get(i)==(list.get(i-1))) //后一项=前一项
    n = list.get(i);
  }
  System.out.println(m+" "+n);
 }

2013A组题八

题干

/**

  • 2013A组题八,B组题九:

  • 带分数:

  • 100可以表示为带分数的形式:100 = 3 + 69258 / 714
  • 还可以表示为:100 = 82 + 3546 / 197
  • 注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)
  • 类似这样的带分数,100有11种表示法

  • 题目要求:
  • 从标准输入读入一个正整数N(N<1000*1000)
  • 程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数
  • 注意:不要求输出每个表示,只统计有多少表示法


  • 例:
  • 用户输入:
  • 100
  • 程序输出:
  • 11

  • 例:
  • 用户输入:
  • 105
  • 程序输出:
  • 6


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

*/

public class A_H_2013 {
 /**
  * (等号右边)1~9分别一次,分数部分必须能够整除
  */
 static int ans = 0;
 static int N ;
 public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  int[] arr = {1,2,3,4,5,6,7,8,9};
  N = sc.nextInt();
  f (arr , 0);
  System.out.println(ans);
  sc.close();
 }
 /**
  * 确认某一个全排列的第k位 
  * @param k
  */
 private static void f  (int[]arr , int k) {
  if(k==9) {  // 全部确认
   check(arr);
//   print(arr);
   return ;
  }
  //选定第k位,移交下一层去确认k+1位
  for(int i=k;i<arr.length;i++) {
   //将第i位与第k位交换
   int t = arr[i];
   arr[i] = arr[k];
   arr[k] = t;
   f (arr , k+1);
   //回溯(换回来)
   t = arr[i];
   arr[i] = arr[k];
   arr[k] = t;
  }
 }
 /**枚举 + 和 / 的位置**/
 private static void check(int[] arr) {
  // + 最多放在第七位    X+XXXXX/XXXX  ---   XXXXXX+XX/X
  for(int i=1 ; i<=7 ; i++) {
   //   / 前面的字符数最多为 9 - i - 1
   int num1 = toInt(arr , 0 , i);  // + 前面的一段整数
   if(num1 >= N) continue; //如果此时+前的数值已经超过了N,则没必要验算了
   for(int j=1 ; j<=8-i ; j++) {
    int num2 = toInt(arr , i , j);
     int num3 = toInt(arr , i+j , 9-i-j);
    if(num2%num3==0&&num1+num2/num3==N) {
     ans++;
    }
   }
  }
 }
 private static int toInt(int[] arr, int pos , int len) {
  int t = 1;
  int ans = 0;
  for(int i=pos+len-1;i>=pos;i--) {
   ans += arr[i]*t;
   t*=10;
  }
  return ans;
 }
}

2013A组题九:

题干
/**

  • 2013年A组题九:
  • C组题十:


  • 剪格子:

  • 如图所示,3 X 3 的格子中填写了一些整数
  • 我们沿着途中的红色线剪开,得到两个部分,每个部分的数字和都是60
  • 本题的要求就是请你编程判定:对于给定的 m X n 的格子中的整数,是否可以
  • 分隔成两个部分,使得这两个区域的数字和相等
  • 如果存在多种解答,请输入包含左上角格子的那个区域包含的格子的最小数目
  • 如果无法分隔,则输出0

  • 程序输入输出格式要求:
  • 程序先读入两个整数 m n 用空格分隔(m , n < 10)
  • 表示表格的宽度和高度
  • 接下来是n 行,每行打出m个正整数,用空格分开,每个整数不大于10000
  • 程序输出:在所有解中,包含左上角的分割区可能包含的最小的格子数目

  • 例如:
  • 用户输入:
  • 3 3
  • 10 1 52
  • 20 30 1
  • 1 2 3

  • 则程序输出:
  • 3

  • 在例如:
  • 用户输入:
  • 4 3
  • 1 1 1 1
  • 1 30 80 2
  • 1 1 1 100

  • 则程序输出:
  • 10

*/

public class A_I_2013 {
 /**
  * dfs 剪枝 回溯
  */
 
 static int[][] g ;
 static int[][] vis;  //标记走过的地方
 static int m ;
 static int n ;
 static int total ;  //总和
 static int ans = Integer.MAX_VALUE ;
 static void dfs(int i,int j,int steps,int sum) {
 //走出边界或者已走过,非法路径直接return
  if(i < 0 || i == n || j<0 || j==m || vis[i][j] ==1)  return;
  
  if(sum == total / 2) {
   ans = Math.min(ans , steps);//记录步数
   return;
  }
  
  if(sum > total / 2)  return;//总和>总数一半,走不通,回到上一个位置
  
  dfs(i+1 , j , steps+1 , sum+g[i][j] ); //down
  dfs(i-1 , j , steps+1 , sum+g[i][j] ); //up
  dfs(i , j-1 , steps+1 , sum+g[i][j] ); //left
  dfs(i , j+1 , steps+1 , sum+g[i][j] ); //right
  vis[i][j] = 0;//回溯,标记为还未经过
 }
 public static void main(String[] args) {
  Scanner sc = new Scanner(System.in);
  //程序先读入两个整数 m n 用空格分隔(m,n<10)
  //表示表格的宽度和高度
   m = sc.nextInt();
   n = sc.nextInt();
   g = new int[n][m];
   vis = new int[n][m];
  for(int i=0;i<n;i++) {
   for(int j=0;j<m;j++) {
    g[i][j] = sc.nextInt();
    total += g[i][j];
   }
  }
  //完成输入
  dfs(0 , 0 , 0 , 0);
  System.out.println(ans);
  sc.close();
 }
}