一、问题 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;
}
}