蓝桥杯

2015蓝桥杯真题

15省7-牌型种数 小明被劫持到X赌城,被迫与其他3人玩牌。 一副扑克牌(去掉大小王牌,共52张),均匀发给4个人,每个人13张。 这时,小明脑子里突然冒出一个问题: 如果不考虑花色,只考虑点数,也不考虑自己得排后的先后顺序,自己手里能拿到的初始牌型组合一共多少种?

思路:这根本就是一道高中排列组合的题,可能感觉很烦,但是多想一想也就有了思路。一个人13张牌,不考虑花色,那就有13种牌型:A、1、2、3、4、5、6、7、8、9、10、J、Q、K。因为一个人13张牌,可以思考对于这13张牌,其中A,1,2,3,....J,Q,K各占多少张。一种牌型,例如A可以有0张,或者4张,其它的牌型同理,最终一个人的总的牌数量等于13张。所以可以用暴力求解的办法来做,每种牌型一个for循环,依次嵌套,它们可以有0张到4张。

 1 public static void main(String args[]) {
 2             int num = 0;
 3             int[] a=new int[13];
 4             for(a[0]=0;a[0]<=4;a[0]++){
 5                 for(a[1]=0;a[1]<=4;a[1]++){
 6                     for(a[2]=0;a[2]<=4;a[2]++){
 7                         for(a[3]=0;a[3]<=4;a[3]++){
 8                             for(a[4]=0;a[4]<=4;a[4]++){
 9                                 for(a[5]=0;a[5]<=4;a[5]++){
10                                     for(a[6]=0;a[6]<=4;a[6]++){
11                                         for(a[7]=0;a[7]<=4;a[7]++){
12                                             for(a[8]=0;a[8]<=4;a[8]++){
13                                                 for(a[9]=0;a[9]<=4;a[9]++){
14                                                     for(a[10]=0;a[10]<=4;a[10]++){
15                                                         for(a[11]=0;a[11]<=4;a[11]++){
16                                                             for(a[12]=0;a[12]<=4;a[12]++){
17                                                                 if(a[0]+a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8]+a[9]+a[10]+a[11]+a[12]==13){
18                                                                     num++;
19                                                                 }
20                                                             }    
21                                                         }    
22                                                     }    
23                                                 }    
24                                             }    
25                                         }    
26                                     }    
27                                 }    
28                             }    
29                         }    
30                     }    
31                 }    
32             }
33             System.out.println(num);
34         }


输出一行,包含一个实数,四舍五入保留小数点后7位,表示圆的面积。

说明:在本题中,输入是一个整数,但是输出是一个实数。

对于实数输出的问题,请一定看清楚实数输出的要求,比如本题中要求保留小数点后7位,则你的程序必须严格的输出7位小数,输出过多或者过少的小数位数都是不行的,都会被认为错误。

实数输出的问题如果没有特别说明,舍入都是按四舍五入进行。

这个题和以前C语言的题不一样,C语言需要的是return,蓝桥杯只需要打印出来就行。

而printf函数的(%.f)机制就可以进行按照多少位自动四舍五入,或者用String.format方法也能够四舍五入。
String.format可以改变原来的数,返回处理后的结果

public class Main { 
	public static void main(String args[]){
	   NumberFormat formatter = NumberFormat.getNumberInstance();
	   formatter.setMaximumFractionDigits(18);
	   Scanner scan=new Scanner(System.in);
	   int r = scan.nextInt();
	   double s=r*r*(Math.PI);
	   String result=String.format("%.7f", s);
//	   System.out.printf("%.7f",s);//方法一
	   System.out.printf(result);//方法二
	   
	}
 }

  

试题 基础练习 分解质因数

样例输入
3 10
[A,B]范围
 
样例输出
3=3
4=2*2
5=5
6=2*3
7=7
8=2*2*2
9=3*3
10=2*5
 
算法思想:1、判断当前是否为质数。2、如果找到一个能够除尽的因数,并且还不是本身,那么就进行循环分解。直到等于本身为止(也就是为质数为止)3、再将最后一位数乘在最后
具体代码如下:
//java中静态方法不能调用非静态方法。
public class Main {
    public static  void main(String [] args){
        for (int i = 3; i < 10; i++) {
        	decompose(i);	
        	System.out.println();
		}
     }

     //因数分解函数
     private static void decompose(int n)
     {
         System.out.print(n+"=");
         for(int i=2;i<=n;i++)
         {
             while (n%i==0&&n!=i)
             {
                 n/=i;//能够除尽,并且不是本身,继续除
                 System.out.print(i+"*");//并且输出当前的i
             }
             if(n==i){
                 System.out.print(i);//输出最后一位
                 break;
             }
         }
     }
}

  

 贪心算法:完美的代价
 
问题描述:
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
 
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible
 
题目分析:
(1):输出为impossible的情况:在判断字符串输出impossible的情况,一共有两种:
1、输入字符串的长度为偶数时,如果发现有单个字符,则输出impossible。
2、输入字符串的长度为单数时,如果发现单个字符的个数大于1,则输出impossible。
(2):输出为交换的最小长度:
1、如果字符串长度为偶数,从左边第一个字符开始,从后往前寻找与第一个字符相同的字符。如果找到,则通过与其右边相邻位置的字符交换位置,
直到换到最后一个位置。下次遍历就从左边第二个字符开始寻找,排好的位置就不用再遍历了。执行与第一个字符相同的操作。
2、如果字符串长度为奇数,从左边第一个字符开始遍历,同样从右边开始找与它相同的字符。其间如果发现了单个数的字符,不必将该字符先交换到中间,而是先计算到中间的次数,累加到次数变量count上。将剩下的字符都交换对称了以后,再移动该字符。
(因为如果该单字符如果是第一个字符,来开始就移动到了中间,后面的字符如果需要跨过中间移动,就会多移动一次)。
代码如下:
public class Main {
    public static void main(String[] args) {
                Scanner scan=new Scanner(System.in);
        int n=scan.nextInt();
        String s=scan.next();
        int end=n-1;
        char[] arr=s.toCharArray();
        int cnt=0;//交换次数
        int oddNum=0;//判断是否有一个单独的奇个数字符
        for (int i = 0; i < end; i++) {//从第一个字符到倒数第二个字符的遍历
            for (int j = end; j >=i ; j--) {//从最后一个字符到第i个字符,寻找与s[i]相同的字符
                if(i==j){//如果没找到
                    if(n%2==0||oddNum==1){//输出impossible的情况 odd已经有一个为奇数次数了,当n为偶数时只要出现一个奇数词
                        System.out.println("Impossible");
                        return;
                    }
                    oddNum++;
                    cnt+=n/2-i;//将该单字符交换到中间位置的次数
                }else if(arr[i]==arr[j]){//找到了的情况
                    for (int j2 = j; j2 < end; j2++) {
                        char temp=arr[j2];
                        arr[j2]=arr[j2+1];
                        arr[j2+1]=temp;
                        cnt++;
                    }
                    end--;
                    break;
                }
            }
        }
        System.out.println(cnt);
    }
 
}
问题描述

很久以前,T王国空前繁荣。为了更好地管理国家,王国修建了大量的快速路,用于连接首都和王国内的各大城市。

为节省经费,T国的大臣们经过思考,制定了一套优秀的修建方案,使得任何一个大城市都能从首都直接或者通过其他大城市间接到达。同时,如果不重复经过大城市,从首都到达每个大城市的方案都是唯一的。

J是T国重要大臣,他巡查于各大城市之间,体察民情。所以,从一个城市马不停蹄地到另一个城市成了J最常做的事情。他有一个钱袋,用于存放往来城市间的路费。

聪明的J发现,如果不在某个城市停下来修整,在连续行进过程中,他所花的路费与他已走过的距离有关,在走第x千米到第x+1千米这一千米中(x是整数),他花费的路费是x+10这么多。也就是说走1千米花费11,走2千米要花费23。

J大臣想知道:他从某一个城市出发,中间不休息,到达另一个城市,所有可能花费的路费中最多是多少呢?

输入格式

输入的第一行包含一个整数n,表示包括首都在内的T王国的城市数

城市从1开始依次编号,1号城市为首都。

接下来n-1行,描述T国的高速路(T国的高速路一定是n-1条)

每行三个整数Pi, Qi, Di,表示城市Pi和城市Qi之间有一条高速路,长度为Di千米。

输出格式

输出一个整数,表示大臣J最多花费的路费是多少。

样例输入1
5
1 2 2
1 3 1
2 4 5
2 5 4
 
样例输出1
135
 
 
 算法思想:受迷宫问题的启发,该题用数据结构中常用的深度搜索算法,输入的数据中第一行是由多少个节点,也就是多少个城市。做成一个n*n的二维矩阵,然后再进行递归深搜遍历。直接上代码,注释详解。
public class Main { 
	static int n;
	static int max=0;
	public static void main(String[] args) {
		Scanner sca = new Scanner(System.in);
		n=sca.nextInt();
		int[][] field=new int[n][n];
	
		for (int i = 0; i < n-1; i++) {
			int temp1=sca.nextInt();
			int temp2=sca.nextInt();
			int temp3=sca.nextInt();
			field[temp1-1][temp2-1]=temp3;
			field[temp2-1][temp1-1]=temp3;
		}
		int MAX=0;
		for (int i = 0; i < n; i++) {
			int max1=0;
			int max2=0;
			boolean[][] flag= new boolean[n][n]; 
			for (int j = i; j < n; j++) {
				if (i!=j&&field[i][j]!=0&&field[j][i]!=0) {
					max = 0;
					flag[i][j] = true;
					flag[j][i] = true;
					dfs(field, i, j, flag, 0);
					max1 = max;
					max = 0;
					flag[j][i] = true;
					flag[i][j] = true;
					dfs(field, j, i, flag, 0);
					max2 = max;
					int temp = 0;
					if (max1 > max2) {
						temp = max1;
					} else {
						temp = max2;
					}
					if (temp > MAX) {
						MAX = temp;
					} 
				}
			}
		}
			int d=11;
			int i = 0;
			int sumAll=0;
			for (int j = 0; j < MAX; j++) {
				sumAll+=d;
				d++;
			}
			System.out.println(sumAll);
	 
	}

	static void dfs(int[][] field,int x,int y,boolean[][] flag,int sum)
	{
		sum+=field[x][y]; //访问到当前节点将到sum计算路程长度
		if(sum>max){//如果当前路径大于最大路径则更改当前路径
			max=sum;
		}
		for (int i = 0; i < n; i++) {
			if(field[y][i]!=0&&flag[y][i]==false){ //进行遍历,因为是深度搜索那么如果传入的x是1,y是2那么下一次只能遍历,以2这个节点开始的其他节点。进行遍历。判断的if语句为需要走的路径存在也就是field[y][i]不为空。这里就没有考虑对角线的元素,因为对角线自己到自己肯定为0。并且判断flag数组当前该节点是否被访问过,如果没访问过,则为真。满足以上两个条件则可以进行遍历下一个城市。
			    flag[y][i]=true;//把下一个这个城市flag置为真代表访问过。
				flag[i][y]=true;//采用的二维数组,对称矩阵 无向图 所以需要把两个地方的状态都改变。
				dfs(field,y,i,flag,sum);//将下一个这个城市进行递归 遍历它的周围
				flag[i][y]=false;//回溯将当前这个点 置为false;
				flag[y][i]=false;
			} 
		}//访问不动了直接return .
		return;	
	}
}

  该题没做到100分,最后一个数据10000条,超时,但是答案跑了20分钟是对的。可以继续优化一些判断条件,减少递归次数。

快速幂取模算法

蓝桥杯中,有很多的时候都会用到取余运算,如斐波拉契数列的余数等题。思路很容易就能想到,但是会出现一个问题就是出现结果超精度范围的问题,所以需要缩小每次的结果,对每次的结果进行求余再进行求和运算等操作。

最近发现了如公式(a+b)%c=(a%c+b%c)%c=(a%c+b)%c等。并且发现乘法也能成立,(a * b) % c = [ (a % c) * ( b % c) ] % c,所以在遇到这些情况,需要及时考虑是否能用这些方法缩小运算结果。

这个题就会用到乘法(a * b) % c = [ (a % c) * ( b % c) ] % c公式的深化,快速幂取模算法。

原博客:快速幂取模算法

  所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余)。在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。我们先从简单的例子入手:求abmodc

int ans = 1;
for(int i = 1;i<=b;i++)
{
   ans = ans * a;
}
ans = ans % c;

  

缺点:这个算法存在着明显的问题,如果a和b过大,很容易就会溢出。

我们先来看看第一个改进方案:在讲这个方案之前,要先看这样一个公式:amod c = (a mod c)mod c

于是不用思考的进行了改进:

既然某个因子取余之后相乘再取余保持余数不变,那么新算得的ans也可以进行取余

int ans = 1;
a = a % c; //加上这一句
for(int i = 1;i<=b;i++)
{
   ans = ans * a;
}
ans = ans % c;

 快速幂算法:

快速幂算法依赖于以下明显的公式:

 

int PowerMod(int a, int b, int c)
{
    int ans = 1;
    a = a % c;
    while(b>0) {
        if(b % 2 = = 1)
        ans = (ans * a) % c;
        b = b/2;
        a = (a * a) % c;
    }
    return ans;
}

  可以看到指数b是按照根号2倍缩小,所以运算较少了很多次,时间复杂度很好。

试题 历届试题 小数第n位

该题会遇到数论的知识:x/d%m = x%(d*m)/d。

第 n 位的后三位,也就是第 n ------ n + 2 位,把第 n + 2 位(含)之前的部分变成整数,再%1000就是我们要的三位数答案,最小的位是第 n + 2 位,想把它变成整数的个位,需要 乘 10n+2 ,也就是 a / b * 10n+2 % 1000 即为答案,因为 n 的范围可能很大,所以就需要用快速幂取模算法 。
可见就是简单的求逆元!但是由于模的是1000,不是素数,不能使用费马小定理和扩展欧几里得来求逆元。需要用下面的公式:
x/d%m = x%(d*m)/d
对应前式,x = a * 10n+2 ,d = b,m = 1000
这样这道题就变成了
[ a * 10 n+2 % (b * 1000) ] / b (式1)
又有公式:
(a * b) % c = [ (a % c) * ( b % c) ] % c
所以式1中的 [ a * 10 n+2 % (b * 1000) ] 部分可以转换为
[ a % (b * 1000) ] * [ 10n+2 % (b * 1000) ] % (b * 1000)
而 [ 10n+2 % (b * 1000) ] 可以通过快速幂取模运算直接求出,代码中用 res 表示 

import java.util.Map;
//java中静态方法不能调用非静态方法。
public class Main { 
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
		int n = sc.nextInt();
		sc.close();
		long mod = b * 1000;
		long res = qPow(10, n + 2, mod);
		long tem = (a % mod * res) % mod;
		System.out.println(String.format("%03d", tem / b));//3位整数形式,不足3位补0
	}
	
	public static long qPow(long a, long b, long c) {
		long res = 1;
		long prod = a;
		while(b > 0) {//用的位运算。
			if((b & 1) == 1) res = (res * prod) % c;//快速幂 公式。
			prod = (prod * prod) % c;
			b >>= 1;
		}
		return res;
	}
}

  RSA解密

        需要用到正整数分解质因数。例如:输入90,打印出90=2*3*3*5。

分析:从1到N先找出最小的质因数,如果等于本身,那么说明只有一个质因数,如果不是,那么将该质因数打印出来,并将N/该质因数作为新的N值进行运算

 算法流程:
1、如果这个质因数敲好等于n,则说明分解质因数结束,打印出来即可。
2、如果n!=k,但是n能够被k整除,则打印出k值,并且将n/k的结果作为新的n值
3、如果n不能被k整除,那么用k+1的结果作为k重复第一步。
public class Main {
	public static void main(String[] args) {
		long res=1001733993063167141L;
		for(int i = 2;i<=res;i++){//符合第三步
			if(res%i==0&&res!=i){//n能够被k整除,并且n不等于k 符合第二步
				System.out.println(i);
				res=res/i;
				 
			}
			if(res==i){//符合第一步打印
				System.out.println(i);
				break;
			}
		}

	}
保留x位小数,并且进行四舍五入。
public class Main {
	public static void main(String[] args) {
		String a=String.format("%.5f", 0.123125);//保留五位小数
		String b=String.format("%.4f", 0.12346);//保留四位小数
		String c=String.format("%.3f", 0.1234);//保留三位小数
		String d=String.format("%.2f", 0.129);
		String e=String.format("%.1f", 0.18);
		System.out.println(a);
		System.out.println(b);
		System.out.println(c);
		System.out.println(d);
		System.out.println(e);
	}
}

  

结果输出:

0.12313
0.1235
0.123
0.13
0.2

原文地址:https://www.cnblogs.com/Alei777/p/14306962.html