练习Day——11

摆动序列(ALGO_9)

题目描述
如果一个序列满足下面的性质,我们就将它称为摆动序列:

  1. 序列中的所有数都是不大于k的正整数;
  2. 序列中至少有两个数。
  3. 序列中的数两两不相等;
  4. 如果第i – 1个数比第i – 2个数大,则第i个数比第i – 2个数小;如果第i – 1个数比第i – 2个数小,则第i个数比第i – 2个数大。
    比如,当k = 3时,有下面几个这样的序列:
    1 2
    1 3
    2 1
    2 1 3
    2 3
    2 3 1
    3 1
    3 2
    一共有8种,给定k,请求出满足上面要求的序列的个数。

输入
输入包含了一个整数k。(k< =20)

输出
输出一个整数,表示满足要求的序列个数。

样例输入
3

样例输出
8

题目解析
参考:http://www.10qianwan.com/articledetail/635659.html
第四个条件可以简化为如果有三个数为:小、中、大,则满足条件的序列为
1:中、大、小 (如果第i – 1个数比第i – 2个数大,则第i个数比第i – 2个数小)
2:中、小、大 (如果第i – 1个数比第i – 2个数小,则第i个数比第i – 2个数大)
可以看出无论如何变化, 中间大小的数的位置序列的都在最左边,当扩充到长度为n的序列时,只要任意三个数满足以上条件,此序列就为符合条件的摆动序列;

1.子问题确定:最长上升子序列告诉我们元素最大值在子问题的使用表达中不可忽视,本题目就是以满足条件序列最大值以及序列长度作为子问题进行解决的;

2.状态:状态数组dp[i][j]表示的含义为:i为所满足条件的序列中的最大值,j为序列长度(i 可以不包含在序列中,如i为4、j为3时,231、241均满足条件);

3.初始状态:当序列长度为2时,即dp[i][2]时,没有所谓的中位数,只有大、小两个数,题目就转换为求排列组合的问题了,即:在i个数中选取2个数进行排列;

4.状态转移方程:
dp[i][j]=dp[i-1][j-1]+dp[i-1][j]
解释:
1.由2.状态解释可知,当长度为 j ,最大值为 i 时,其一定包含长度为 j,最大值为 i-1 的序列,因为由 i-1 到 i 其最大值变大了,所以一定包含;即:dp[i][j]=dp[i-1][j]+一个数
2.由整体概况解释可知,如果要满足题目序列,则任意三个数其中间大小的数应该为最左边;在推导过程中可知,当再增加一个较大的数值时应该舍弃原满足条件中的小,将这个新数添加到新的三个序列中去;

dp表中的i行j列其实就相当于在i-1行j-1列中插入一个i,以i=3,j=3举例:它就相当于在 ‘1 2 ’和 ‘2 1’序列里面插入3这个数字,插入后要满足题目第四点给出的情况,我们只能是在‘ 2 1 ’里面插,因为在‘ 1 2 ’里面插无论如何也不能满足中间的数在最左边,而对于 ‘2 1 ’来说只能插在最右边和中间,因为i是最大的数字,i不能在左边。所以有两种插入情况。

推广到更大的长度来说,有一半的排列是不能插的,而对于另一半来说,这个最大的数可以插在最右边和倒数第二个位置。如果再往左边的话,就会不满足题目要求了。所以相当于(i-1)(j-1)的情况除2再乘2等于本身。所以,加的另一个数位dp[i-1][j-1]:在长度为 j-1 的序列中,插入更大的数 i

import java.util.Scanner;

//摆动序列
public class Main {
	public static int dp[][];
	public static void main(String[]args) {
		Scanner scan=new Scanner(System.in);
		int k=scan.nextInt();
		scan.close();
		
		dp=new int[k+1][k+1];//状态数组,dp[i][j]表示满足最大值为i,长度为j的排列方式有几个
		
		//初始化,最大值为i,长度为2的排列方式有i*(i-1)个
		for(int i=2;i<=k;i++) {
			dp[i][2]=i*(i-1);
		}
		//逐渐向状态数组中加数
		for(int i=3;i<=k;i++) {
			for(int j=3;j<=k;j++) {
				dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
			}
		}
		
		int sum=0;
		for(int i=2;i<=k;i++) {
			sum+=dp[k][i];
		}
		
		System.out.println(sum);
	}

}

乘积最大(ALGO_17)

题目描述
今年是国际数学联盟确定的“2000——世界数学年”,又恰逢我国著名数学家华罗庚先生诞辰90周年。在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加。活动中,主持人给所有参加活动的选手出了这样一道题目:

设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大。

同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子:

有一个数字串:312, 当N=3,K=1时会有以下两种分法:

312=36
31
2=62

这时,符合题目要求的结果是:31*2=62

现在,请你帮助你的好朋友XZ设计一个程序,求得正确的答案。

输入
程序的输入共有两行:
第一行共有2个自然数N,K(6≤N≤40,1≤K≤6)
第二行是一个长度为N的数字串。

输出
输出所求得的最大乘积(一个自然数)。

样例输入
4 2
1231

样例输出
62

题目解析
状态转移方程:*dp[i][j]=Math.max(dp[i][j],dp[m][j-1]fun(m+1,i,num))
dp[i][j]表示表示长度为i,有j个乘号的数字大小。要找最大值,因此如果新情况比之前的值更大,则更新dp值,dp初始值为数字不加乘号时的值。
dp[m][j-1]表示在第m个数字和第m+1个数字之间插入一个乘号时,第m个数字及之前中间插入j-1个乘号时数字的大小;fun(m+1,i,num)表示m+1之后的数字的大小。两者相乘得到新的值。

import java.util.Scanner;

//乘积最大
public class Main {
	public static void main(String[]args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int k=scan.nextInt();
		String str=scan.next();
		scan.close();
		
		int num[]=new int[n+1];
		for(int i=1;i<n+1;i++)
			num[i]=str.charAt(i-1)-'0';
		
		int dp[][]=new int[n+1][k+1];//dp[i][j]表示长度为i,有j个乘号的数字大小
		for(int i=0;i<n+1;i++) {
			dp[i][0]=fun(1,i,num);//初始化,零个乘号时,dp[i][j]为它本身
		}
		
		for(int i=1;i<n+1;i++) {
			for(int j=1;j<=k && j<i;j++) {//j<i,乘号的个数不能比数字长度还大
				for(int m=1;m<i;m++) {
					dp[i][j]=Math.max(dp[i][j],dp[m][j-1]*fun(m+1,i,num));
				}
			}
		}
		
		System.out.print(dp[n][k]);
	}

	private static int fun(int a, int b, int[] num) {
		int sum=0;
		for(int i=a;i<=b;i++) {
			sum=sum*10+num[i];
		}
		return sum;
	}
}

进制转换(ALGO_16)

题目描述
程序提示用户输入三个字符,每个字符取值范围是0-9,A-F。然后程序会把这三个字符转化为相应的十六进制整数,并分别以十六进制,十进制,八进制输出。

输入
输入只有一行,即三个字符。

输出
三个整数,中间用空格隔开。

样例输入
FFF

样例输出
FFF 4095 7777

import java.util.Scanner;

//进制转换
public class Main {
	public static void main(String[]args) {
		Scanner scan=new Scanner(System.in);
		String str=scan.next();
		scan.close();
		int a=Integer.valueOf(str, 16);//字符串转换为16进制整数
		String b=Integer.toString(a, 16).toUpperCase();
		String c=Integer.toString(a, 10);
		String d=Integer.toString(a, 8);
		System.out.print(b+" "+c+" "+d);
	}
}

集合运算

题目描述
给出两个整数集合A、B,求出他们的交集、并集以及B在A中的余集。

输入
第一行为一个整数n,表示集合A中的元素个数。
第二行有n个互不相同的用空格隔开的整数,表示集合A中的元素。
第三行为一个整数m,表示集合B中的元素个数。
第四行有m个互不相同的用空格隔开的整数,表示集合B中的元素。
集合中的所有元素均为int范围内的整数,n、m< =1000。

输出
第一行按从小到大的顺序输出A、B交集中的所有元素。
第二行按从小到大的顺序输出A、B并集中的所有元素。
第三行按从小到大的顺序输出B在A中的余集中的所有元素。

样例输入
5
1 2 3 4 5
5
2 4 6 8 10

样例输出
2 4
1 2 3 4 5 6 8 10
1 3 5

import java.util.Arrays;
import java.util.Scanner;

//集合运算
public class Main {
	public static int x=0,y=0,z=0;//用来记录三个集合的长度
	public static void main(String[]args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		int A[]=new int[n];
		for(int i=0;i<n;i++)
			A[i]=scan.nextInt();
		
		int m=scan.nextInt();
		int B[]=new int[m];
		for(int i=0;i<m;i++)
			B[i]=scan.nextInt();
		scan.close();
		
		Arrays.sort(A);
		Arrays.sort(B);
		int C[]=new int[1000];
		int D[]=new int[1000];
		int E[]=new int[1000];//C、D、E分别为A、B的交集、并集、余集
		
		fun1(A,B,C);
		fun2(A,B,D);
		fun3(A,B,E);
		
		for(int i=0;i<x;i++)
			System.out.print(C[i]+" ");
		System.out.println();
		
		for(int i=0;i<y;i++)
			System.out.print(D[i]+" ");
		System.out.println();
		
		for(int i=0;i<z;i++)
			System.out.print(E[i]+" ");
		System.out.println();
	}

	//求交集
	private static void fun1(int[] a, int[] b,int c[]) {
		int i=0,j=0;
		while(i<a.length && j<b.length) {
			if(a[i]==b[j]) {
				c[x]=a[i];
				i++;
				j++;
				x++;
			}
			else if(a[i]>b[j]) {
				j++;
			}
			else {
				i++;
			}
		}
	}
    //求并集
	private static void fun2(int[] a, int[] b,int []d) {
		int i=0,j=0;
		while(i<a.length && j<b.length) {
			if(a[i]==b[j]) {
				d[y]=a[i];
				i++;
				j++;
				y++;
			}
			else if(a[i]>b[j]) {
				d[y]=b[j];
				j++;
				y++;
			}
			else {
				d[y]=a[i];
				i++;
				y++;
			}
		}
		while(i<a.length) {
			d[y]=a[i];
			i++;
			y++;
		}
		while(j<b.length) {
			d[y]=b[j];
			j++;
			y++;
		}
	}
    //求余集
	private static void fun3(int[] a, int[] b,int []e) {
		int i=0,j=0;
		while(i<a.length && j<b.length) {
			if(a[i]==b[j]) {
				i++;
				j++;
			}
			else if(a[i]>b[j]) {
				j++;
			}
			else {
				e[z]=a[i];
				i++;
				z++;
			}
		}
		while(i<a.length) {
			e[z]=a[i];
			i++;
			z++;
		}
	}

}

完数

题目描述
一个数如果恰好等于它的因子之和,这个数就称 为“完数”。例如,6的因子为1、2、3,而6=1+2+3,因此6就是“完数”。又如,28的因子为1、2、4、7、14,而 28=1+2+4+7+14,因此28也是“完数”。编写一个程序,判断用户输入的一个数是否为“完数”。

输入
输入只有一行,即一个整数。

输出
输出只有一行,如果该数为完数,输出yes,否则输出no。

样例输入
6

样例输出
yes

import java.util.Scanner;

//完数
public class Main {
	public static void main(String[]args) {
		Scanner scan=new Scanner(System.in);
		int n=scan.nextInt();
		scan.close();
		int sum=0;
		for(int i=1;i<n;i++) {
			if(n%i==0) {
				sum+=i;
			}
		}
		if(n==sum)
			System.out.println("yes");
		else
			System.out.println("no");
	}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值