倒计时4

一、问题 1434: [蓝桥杯][历届试题]回文数字

时间限制: 1Sec 内存限制: 128MB 提交: 3302 解决: 1442

题目描述
观察数字:12321,123321 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的。这样的数字叫做:回文数字。

本题要求你找到一些5位或6位的十进制数字。满足如下要求:
该数字的各个数位之和等于输入的整数。
输入
一个正整数 n (10< n< 100), 表示要求满足的数位和。
输出
若干行,每行包含一个满足要求的5位或6位整数。
数字按从小到大的顺序排列。
如果没有满足条件的,输出:-1
样例输入
44
样例输出
99899
499994
589985
598895
679976
688886
697796
769967
778877
787787
796697
859958
868868
877778
886688
895598
949949
958859
967769
976679
985589
994499

package day6;

import java.util.Scanner;

public class t1434 {
	static int count=0;
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		hw_5(n);
		hw_6(n);
		if(count==0){
			System.out.println("-1");
		}
		
	}
	public static void hw_5(int n){
		for(int i=1;i<=9;i++){
			for(int j=0;j<=9;j++){
				for(int k=0;k<=9;k++){
					if(i*2+j*2+k==n){
						count++;
						System.out.println(i+""+j+""+k+""+j+""+i);
					}
				}
			}
		}
	}
	public static void hw_6(int n){
		for(int i=1;i<=9;i++){
			for(int j=0;j<=9;j++){
				for(int k=0;k<=9;k++){
					if(i*2+j*2+k*2==n){
						count++;
						System.out.println(i+""+j+""+k+""+k+""+j+""+i);
					}
				}
			}
		}
	}
}

二、问题 1436: [蓝桥杯][2014年第五届真题]地宫取宝

时间限制: 1Sec 内存限制: 128MB 提交: 1045 解决: 258

题目描述
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 3 2
1 2 3
2 1 5
样例输出
14
代码来源 记忆搜索=bfs+记录

package day6;

import java.util.Scanner;

public class t1436_right_2 {
	private static long N = 1000000007;
	private static int n,m,k;
	private static int map[][] = new int[50][50];  //记录迷宫
	
	//dp中,四个参数各代表坐标X,Y、手中持有宝物数量、手中宝物的最大值
	private static int dp[][][][] = new int[50][50][15][15]; 
	
	public static void init(){
        for(int i=0;i<50;i++){
            for(int j=0;j<50;j++){
                for(int k=0;k<15;k++){
                    for(int l=0;l<15;l++) 
                    	dp[i][j][k][l] = -1;
                }
            }
        }
    }
	
	public static int DFS(int x, int y, int num, int max){
		//记忆化搜索,首先先检查该路径是否已经走过
		if(dp[x][y][num][max+1]!=-1){
			//说明已经走过这个条路径,就不用再次走
			//因为宝物有可能为0所以定义max时用最小值-1 这就导致无法作为下标使用  
			//实际上如果测试数据中宝物价值没有0	,将所有的+1 去掉也是可以的   
			//这里的话如果去掉肯定是有些数据不对的,不信可以提交试一下,根本过不了
			return  dp[x][y][num][max+1];
		}
		
		//到达边界
		if(x==n-1 && y==m-1){
			/*到达左下角有两种情况成功
			 * 1.当前手中的数量满足k,这时不拿会成功
			 * 2.当前手中的数量刚好差一个,然后地下的宝物大于手中的max,这时也会成功
			 */
			if(num==k || (num==k-1 && max<map[x][y])){
				return dp[x][y][num][map[x][y]]=1;		
			}else{
				return dp[x][y][num][max+1]=0;		//不满足条件,这里的max+1原因同上
			}
		}
		
		/*拿和不拿的两种情况:
		 * 1.手中的max大于地下宝物价值,此时可拿可不拿
		 * 2.手中的max小于地下宝物价值,此时只能不拿
		 */
		long s = 0;
		if(x<n-1){//向下搜索
			if(max<map[x][y]){//可拿可不拿,不拿的情况可以想成是不符合条件所以不拿,这样来说就可以将其和不能拿一起处理           
				s += DFS(x+1, y, num+1, map[x][y]); 
			}
			s += DFS(x+1, y, num, max);//不拿,与不能拿时写在一起,这点很重要!
			s%=N;
		}
		
		if(y<m-1){//向右搜索
			if(max<map[x][y]){//可拿可不拿,不拿的情况可以想成是不符合条件所以不拿,这样来说就可以将其和不能拿一起处理           
				s += DFS(x, y+1, num+1, map[x][y]); 
			}
			s += DFS(x, y+1, num, max);//不拿,与不能拿时写在一起,这点很重要!
			s%=N;
		}
		
		return  dp[x][y][num][max+1]=(int) s;
		
	}
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		n = scan.nextInt();
		m = scan.nextInt();
		k = scan.nextInt();
		for(int i=0; i<n; i++){
			for(int j=0; j<m; j++){
				map[i][j] = scan.nextInt();
			}
		}
		init();
		DFS(0, 0, 0, -1);
		System.out.println(dp[0][0][0][0]);
		
		
	}
 
}

三、问题 1439: [蓝桥杯][历届试题]小朋友排队

时间限制: 1Sec 内存限制: 128MB 提交: 734 解决: 115

题目描述
n 个小朋友站成一排。现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友。

每个小朋友都有一个不高兴的程度。开始的时候,所有小朋友的不高兴程度都是0。

如果某个小朋友第一次被要求交换,则他的不高兴程度增加1,如果第二次要求他交换,则他的不高兴程度增加2(即不高兴程度为3),依次类推。当要求某个小朋友第k次交换时,他的不高兴程度增加k。

请问,要让所有小朋友按从低到高排队,他们的不高兴程度之和最小是多少。

如果有两个小朋友身高一样,则他们谁站在谁前面是没有关系的。

样例说明
首先交换身高为3和2的小朋友,再交换身高为3和1的小朋友,再交换身高为2和1的小朋友,每个小朋友的不高兴程度都是3,总和为9。
数据规模和约定
对于100%的数据,1< =n< =100000,0< =Hi< =1000000。

输入
输入的第一行包含一个整数n,表示小朋友的个数。
第二行包含 n 个整数 H1 H2 … Hn,分别表示每个小朋友的身高。
输出
输出一行,包含一个整数,表示小朋友的不高兴程度和的最小值。
样例输入
3
3 2 1
样例输出
9
代码一:时间超限64%

package day6;

import java.util.Scanner;

public class t1439 {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int [][]num=new int[n][2];
		for(int i=0;i<n;i++){
			num[i][0]=sc.nextInt();
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<n-i-1;j++){
				if(num[j][0]>num[j+1][0]){
					int t=num[j][0];
					num[j][0]=num[j+1][0];
					num[j+1][0]=t;
					
					t=num[j][1];
					num[j][1]=num[j+1][1];
					num[j+1][1]=t;
					
					num[j][1]++;
					num[j+1][1]++;
				}
			}
		}
		int res=0;
		for(int i=0;i<n;i++){
			int t=num[i][1];
			int sum=0;
			for(int j=1;j<=t;j++){
				sum+=j;
			}
			res+=sum;
		}
		System.out.println(res);
	}
}

代码二:归并排序,树状数组,正确

package day6;

import java.util.*;
public class t1439_right {
 
public static class num //内部类
{
	public long h;//用long,否则会出错
	public long t;//用long,否则会出错
}
static num num1[]=new num[100001];//一开始开了100005个,但是造成了有一组测试数据超时
static num num2[]=new num[100001];//
	public static void main(String[] args) {
 
		for(int i=0;i<100001;i++)//对内部类对象初始化
		{
			num1[i]=new num();
			num2[i]=new num();
		}
		Scanner input=new Scanner(System.in);
		int n=input.nextInt();
		for(int j=0;j<n;j++)
		{
			num1[j].h=input.nextInt();
		}
		merge(num1,0,n-1);
		long sum=0;//必须用long,否则会错误
		for(int k=0;k<n;k++)
		{
			//System.out.println(num1[k].h+" "+num1[k].t);
			sum+=(num1[k].t*(num1[k].t+1))/2;//等差数列求和公示 
		}
		
		System.out.println(sum);
}
	public static void merge(num a[],int left,int right)
	{
		if(left==right)   //终止递归的条件
		{
			return;
		}
		int mid=(left+right)/2;
		merge(a,left,mid);
		merge(a,mid+1,right);
		int p=left;
		int q=mid+1;
		int i=left;
	     while(p<=mid && q<=right)
	     {
	    	 if(a[p].h>a[q].h)
	    	 {
	    		 a[q].t+=mid+1-p;//如果左数组第一个元素比右数组第一个元素大,因为左右数组都是从小到大排序的
//所以左数组所有的元素(mid+1-p个)都大于右数组第一个元素;
 num2[i++]=a[q++];//注意这里交换的是类对象,这是归并排序的核心知识
	    	 }
	    	 else
	    	 {
	    		 a[p].t+=q-1-mid;//左数组的第一个元素小于或者等于右数组的第一个元素,q-1-mid==0,在右数组中,q所指的元素前面的元素就是小于p所指的元素,q-1-mid就是q所指元素的前边元素的个数;
	    		 num2[i++]=a[p++];
	    	 }
	     }
	     while(q<=right)//右数组有剩余,说明左数组的元素都比右数组剩下的元素小
	     {
	    	num2[i++]=a[q++];
	     }
	     q--;//在前边判断循环终止时q=last+1,所以循环终止,所以这里需要减去1
	     while(p<=mid)
	     {
	    	 a[p].t+=q-mid;
	    	num2[i++]=a[p++];
	     }
	     
	   
	    int j=left;
	     for(;j<=right;j++)
	     {
	    	 a[j]=num2[j];//将排序好的类对象数组传给原类对象数组
	     }
		
	}
}

四、问题 1440: [蓝桥杯][2013年第四届真题]带分数

时间限制: 1Sec 内存限制: 128MB 提交: 456 解决: 251

题目描述
100 可以表示为带分数的形式:100 = 3 + 69258 / 714。
还可以表示为:100 = 82 + 3546 / 197。
注意特征:带分数中,数字1~9分别出现且只出现一次(不包含0)。
类似这样的带分数,100 有 11 种表示法。
输入
从标准输入读入一个正整数N (N< 1000*1000)
输出
程序输出该数字用数码1~9不重复不遗漏地组成带分数表示的全部种数。
注意:不要求输出每个表示,只统计有多少表示法!
样例输入
100
样例输出
11
思路:全排列 n=a+b/c
a < n
b > c
b % c==0
结果说答案错误一半,我死了,只给了一个案例,找不出毛病

package day6;

import java.util.Scanner;

public class t1440 {
	static int n;
	static int tt;
	static int res=0;
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		n=sc.nextInt();
		int []num={1,2,3,4,5,6,7,8,9};
		int tn=n;
		while(tn!=0){
			tt++;
			tn=tn/10;
		}
		qpl(num, 0);
		System.out.println(res);
		
	}
	
	public static void qpl(int []num,int i){
		if(i==num.length){
//			System.out.println("ok");
			jud(num);
			return;
		}
		for(int j=i;j<num.length;j++){
			swap(num, i, j);
			qpl(num, i+1);
			swap(num, i, j);
		}
	}
	public static void swap(int []num,int x,int y){
		int t=num[x];
		num[x]=num[y];
		num[y]=t;
	}
	public static void jud(int []num){
		//n=a+b/c   b>c  a:1-tt位  bc=9-a位  b为bc/2~bc-1位  c为bc-b位
		int a,b,c;
		for(int i=0;i<tt;i++){
			a=0;
			for(int ti=0;ti<=i;ti++){
				a+=num[ti]*Math.pow(10, ti);
			}
			for(int j=(9-i)/2;j<9-i-1;j++){
				b=0;c=0;
				for(int ti=i+1;ti<=j;ti++){
					b+=num[ti]*Math.pow(10, ti-i-1);
				}
				for(int ti=j+1;ti<num.length;ti++){
					c+=num[ti]*Math.pow(10, ti-j-1);
				}
				if(b%c==0){
					if(a+b/c==n){
						res++;
//						System.out.println(a+" "+b+" "+c);
//						for(int i1=0;i1<9;i1++){
//							System.out.print(num[i1]+" ");
//						}
//						System.out.println();
					}
				}
				
			}
			
		}
	}
}

正确代码:之前写的

import java.util.Scanner;

public class Main {
	static int res=0;
	static int sr=0;
	public static void main(String[] args) {
		int []num={1,2,3,4,5,6,7,8,9};
		Scanner sc=new Scanner(System.in);
		sr=sc.nextInt();
		qp(num, 0);
		
		System.out.println(res);
	}
	
	public static void test(int []num){
		
		for(int i=1;i<=8;i++){//定义A的长
			//BC共有9-i位长,j为B的长,k是C的长
			int j,k;
			if((9-i)%2==0){
				j=(9-i)/2;
			}else{
				j=(9-i)/2+1;
			}
			for(;j<=(9-i-1);j++){
				k=9-i-j;
//				if(num[i+j-1]%num[num.length-1]==0){
					int A=0;
					for(int a=0;a<i;a++){
						A+=num[a];
						if(a!=i-1){
							A*=10;
						}
					}
					int B=0;
					for(int a=i;a<i+j;a++){
						B+=num[a];
						if(a!=i+j-1){
							B*=10;
						}
					}
					int C=0;
					for(int a=i+j;a<num.length;a++){
						C+=num[a];
						if(a!=num.length-1){
							C*=10;
						}
					}
//					if(A==82&&B==3456){
//						System.out.println(A+","+B+","+C);
//					}
					
					
					if(B%C==0){
						if(A+B/C==sr){
							res++;
//							System.out.println(A+","+B+","+C);
						}
					}
//				}else{
//					
//				}
			}
		}
	}
	
	
	/**
	 * 全排列
	 * */
	public static void qp(int []num,int i){
		if(i==num.length){
			test(num);
//			if(num[0]==8&&num[1]==2&&num[2]==3&&num[3]==4&&num[4]==5&&num[5]==6){
//				for(int j=0;j<num.length;j++){
//					System.out.print(num[j]+" ");
//				}
//				System.out.println();
//			}
			
		}else{
			for(int t=i;t<num.length;t++){
				swap(num, i, t);
//				qp(num,t+1);  //不许在这里再出错了!!!!!
				qp(num,i+1);
				swap(num, i, t);
			}
		}
	}
	public static void swap(int []num,int i,int j){
		int t=num[i];
		num[i]=num[j];
		num[j]=t;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值