2014年第五届蓝桥杯JavaA组

第1题:猜年龄

小明带两个妹妹参加元宵灯会。别人问她们多大了,她们调皮地说:“我们俩的年龄之积是年龄之和的6倍”。小明又补充说:“她们可不是双胞胎,年龄差肯定也不超过8岁啊。”

请你写出:小明的较小的妹妹的年龄。

注意: 只写一个人的年龄数字,请通过浏览器提交答案。不要书写任何多余的内容。

public class Main {
	
	public static void main(String[] args) {
		for(int i = 1;i <= 20;i++) { //i 是大妹妹的年龄
			for(int j = 1;j < i;j++) { //j 是小妹妹的
				if(i - j <= 8 && i * j == (i + j) * 6) {
					System.out.println(j);
				}
			}
		}
	}
}

第2题:李白打酒

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒2斗。他边走边唱:

无事街上走,提壶去打酒。
逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店5次,遇到花10次,已知最后一次遇到的是花,他正好把酒喝光了。

请你计算李白遇到店和花的次序,可以把遇店记为a,遇花记为b。则:babaabbabbabbbb 就是合理的次序。像这样的答案一共有多少呢?请你计算出所有可能方案的个数(包含题目给出的)。

注意:通过浏览器提交答案。答案是个整数。不要书写任何多余的内容。
————————————————————————————————————————————————————————
统计方案数量,一般是深搜

public class Main {
	static int ans = 0;
	
	public static void main(String[] args) {
		f(5, 9, 2);//5个店,9个花,2斗酒的合理排列的数目
		System.out.println(ans);
	}

	private static void f(int dian, int hua, int jiu) {
		if(dian == 0 && hua == 0 && jiu == 1) ans++;//酒得剩一斗,因为最后还得遇一个花
		if(dian > 0) f(dian - 1, hua, jiu * 2);//消耗一个店,酒翻倍
		if(hua > 0) f(dian, hua - 1, jiu - 1);
	}
}

第3题:神奇算式

由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。

比如:

210 x 6 = 1260
8 x 473 = 3784
27 x 81 = 2187

都符合要求。

如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式。

请填写该数字,通过浏览器提交答案,不要填写多余内容(例如:列出所有算式)。
——————————————————————————————————————————————————
答案:12

import java.util.Arrays;

public class Main {
	static int ans = 0;
	
	public static void main(String[] args) {
		for(int i = 1;i <= 9;i++) {
			for(int j = 0;j <= 9;j++) {
				if(i != j) {
					for(int k = 0;k <= 9;k++) {
						if(k != i && k != j) {
							for(int l = 0;l <= 9;l++) {
								if(l != i && l != j && l!= k) {
									int src = i * 1000 + j * 100 + k * 10 + l;//i j k l 的四位数
									//验证两部分的积,是否由 i j k l 组成
									if(j != 0) {//最高位不能是0
										int r1 = i * (j * 100 + k * 10 + l);//枚举 * 的位置,1位 * 3位
										if(check(src, r1)) {
											ans++;
										}
									}
									if(k != 0) {
										int r2 = (i * 10 + j) * (k * 10 + l);//枚举 * 的位置,2位 * 2位
										//下面这句是为了验证不存在 前部分 = 后部分的情况
//										if((i * 10 + j) == (k * 10 + l)) System.out.println(i + " " + j + " " + k + " " + l);
										if((i * 10 + j) < (k * 10 + l) && check(src, r2)) {	//只验证 前部分 < 后部分的情况,避免交换律										
											ans++;
										}
									}
//									if(l != 0) {  这个部分,前面 1位 * 3位的时候已经出现过了,只是前后顺序不同,交换律只能算一种
//										int r3 = (i * 100 + j * 10 + k) * l;//枚举 * 的位置,3位 * 1位
//										if(check(src, r3)) {
//											ans++;
//										}
//									}
								}
							}
						}
					}
				}
			}
		}
		System.out.println(ans);//也可以无视交换律带来的重复,直接在最后 ans/2
	}

	private static boolean check(int src, int r) {
		//先转字符串
		String str = src + "";
		String rstr = r + "";
 		//排序
		char[] srcArr = str.toCharArray();
		char[] rArr = rstr.toCharArray();
		Arrays.sort(srcArr);
		Arrays.sort(rArr);
		//比较
		return Arrays.equals(srcArr, rArr);
	}
}

另个版本:

public class Main {
	static int ans;//12
	
	public static void main(String[] args) {
		for(int a = 1;a <= 9;a++) {
			for(int b = 0;b <= 9;b++) {
				if(a == b) continue;
				for(int c = 0;c <= 9;c++) {
					if(c == b || c == a) continue;
					for(int d = 0;d <= 9;d++) {
						if(d == c || d == b || d == a) continue;
						//枚举样例中 x 号的三个位置
						int num1 = a * 100 + b * 10 + c;
						int num11 = d;
						int sum1 = num1 * num11;
						if(check(a, b, c, d, sum1)) ans++;
						
						int num2 = a;
						int num22 = b * 100 + c * 10 + d;
						int sum2 = num2 * num22;
						if(check(a, b, c, d, sum2)) ans++;
						
						int num3 = a * 10 + b;
						int num33 = c * 10 + d;
						int sum3 = num3 * num33;
						if(check(a, b, c, d, sum3)) ans++;
					}
				}
			}
		}
		
		System.out.println(ans / 2);
	}

	private static boolean check(int a, int b, int c, int d, int sum) {
		String aa = a + "";
		String bb = b + "";
		String cc = c + "";
		String dd = d + "";
		String str = sum + "";
		if(str.length() != 4) return false;
		if(!str.contains(aa)) return false;
		if(!str.contains(bb)) return false;
		if(!str.contains(cc)) return false;
		if(!str.contains(dd)) return false;
		return true;
	}
}

第4题:写日志
在这里插入图片描述

public class Main {
	static class A
	{
		private static int n = 1;
		
		public static void write(String msg)
		{
			String filename = "t" + n + ".log";
			n = n % 3 + 1;//(++n) % 4 == 0 ? 1 : n;
			System.out.println("write to file: " + filename + " " + msg);
		}
	}
	
	public static void main(String[] args) {
		for(int i = 0;i < 10;i++) {//循环10次测试
			A.write("msg");
		}
	}
}

第5题:锦标赛

如果要在n个数据中挑选出第一大和第二大的数据(要求输出数据所在位置和值),使用什么方法比较的次数最少?我们可以从体育锦标赛中受到启发。

如图【1.png】所示,8个选手的锦标赛,先两两捉对比拼,淘汰一半。优胜者再两两比拼…直到决出第一名。

第一名输出后,只要对黄色标示的位置重新比赛即可。

下面的代码实现了这个算法(假设数据中没有相同值)。

代码中需要用一个数组来表示图中的树(注意,这是个满二叉树, 不足需要补齐)。它不是存储数据本身,而是存储了数据的下标。

第一个数据输出后,它所在的位置被标识为-1

class A{
   	//a 表示待处理的数据,长度如果不是2的次幂,则不足位置补为-1
	static void pick(int[] a)
	{
		int n = 1;
		while(n<a.length) n *= 2;
	
	
	int[] b = new int[2*n-1];
	for(int i=0; i<n; i++){ 
		if(i<a.length) 
			b[n-1+i] = i;
		else
			b[n-1+i] = -1;
	}
	
	//从最后一个向前处理
	for(int i=b.length-1; i>0; i-=2){
		if(b[i]<0){
			if(b[i-1]>=0)
				b[(i-1)/2] = b[i-1]; 
			else
				b[(i-1)/2] = -1;
		}
		else{
			if(a[b[i]]>a[b[i-1]])
				b[(i-1)/2] = b[i];
			else
				b[(i-1)/2] = b[i-1];
		}
	}
	
	//输出树根
	System.out.println(b[0] + ": " + a[b[0]]);
	
	//值等于根元素的位置需要重新pk
	pk(a,b,0,b[0]);
	
	//再次输出树根
	System.out.println(b[0] + ": " + a[b[0]]);
}

// a 表示待处理数据,b 二叉树,k 当前要重新比拼的位置,v 已经决胜出的值	
static void pk(int[] a, int[] b, int k, int v)
{
	
	int k1 = k*2+1;
	int k2 = k1 + 1;
	
	if(k1>=b.length || k2>=b.length){
		b[k] = -1;
		return;
	}
	
	if(b[k1]==v) 
		pk(a,b,k1,v);
	else
		pk(a,b,k2,v);
	
	
	//重新比较
	if(b[k1]<0){
		if(b[k2]>=0)
			b[k] = b[k2]; 
		else
			b[k] = -1;
		return;
	}
	
	if(b[k2]<0){
		if(b[k1]>=0)
			b[k] = b[k1]; 
		else
			b[k] = -1;
		return;
	}
	
	if(________a[b[k1]] > a[b[k2]]_________)  //填空
		b[k] = b[k1];
	else
		b[k] = b[k2];
	}
}

请仔细分析流程,填写缺失的代码。

通过浏览器提交答案,只填写缺失的代码,不要填写已有代码或其它说明语句等。
在这里插入图片描述
第6题:六角填数

如图【1.png】所示六角形中,填入1~12的数字。

使得每条直线上的数字之和都相同。

图中,已经替你填好了3个数字,请你计算星号位置所代表的数字是多少?

请通过浏览器提交答案,不要填写多余的内容。
在这里插入图片描述
——————————————————————————————————————————————————————————
考点:全排列
本题是无重复元素的全排列,有重复的,可以使用set

给这几个空格子编上号,进行全排列的试探
在这里插入图片描述
这几条线也编号
在这里插入图片描述

public class Main {
	static int[] arr = {2,4,5,6,7,9,10,11,12};
	
	public static void main(String[] args) {
		f(0);
	}

	private static void f(int k) {
		if(k == 9) {
			check();
			return ;
		}
		for(int i = k;i < 9;i++) {
			int t = arr[k];
			arr[k] = arr[i];
			arr[i] = t;
			
			f(k + 1);
			
			t = arr[k];
			arr[k] = arr[i];
			arr[i] = t;
		}
	}

	private static void check() {
		int r1 = 1 + arr[0] + arr[3] + arr[5]; //r1 表示1号线上的和
		int r2 = 1 + arr[1] + arr[4] + arr[8]; 
		int r3 = 8 + arr[0] + arr[1] + arr[2]; 
		int r4 = 11 + arr[3] + arr[6]; 
		int r5 = 3 + arr[2] + arr[4] + arr[7]; 
		int r6 = arr[5] + arr[6] + arr[7] + arr[8]; 
		
		if(r1 == r2 && r2 == r3 && r3 == r4 && r4 == r5 && r5 == r6) {
			System.out.println("符合条件的排列为:");
			for(int num : arr) {
				System.out.print(num + " ");
			}
			System.out.println();
			System.out.println("*处的值为:" + arr[3]);
		}
	}
}

第7题:绳圈

今有 100 根绳子,当然会有 200 个绳头。

如果任意取绳头两两配对,把所有绳头都打结连接起来。最后会形成若干个绳圈(不考虑是否套在一起)。

我们的问题是:请计算最后将形成多少个绳圈的概率最大?

注意:结果是一个整数,请通过浏览器提交该数字。不要填写多余的内容。
—————————————————————————————————————————————————————————
在这里插入图片描述在这里插入图片描述

public class Main {
	static double[][] f = new double[101][101];
	
	public static void main(String[] args) {
		f[1][1] = 1;
		for(int sheng = 2; sheng <= 100;sheng++) {
			f[sheng][1] = f[sheng - 1][1] * (sheng - 1) * 2 / (2 * sheng - 1);
			for(int quan = 2;quan <= sheng;quan++) {
				f[sheng][quan] = (f[sheng - 1][quan - 1] + f[sheng - 1][quan] * (sheng - 1) * 2) / (2 * sheng - 1); 
			}
		}
		
		double p = -1;//概率
		int ans = -1;//记录概率最大的相应圈数
		//迭代圈
		for(int quan = 1;quan <= 100;quan++) {
			if(f[100][quan] > p) {
				p = f[100][quan];
				ans = quan;
			}
		}
		System.out.println(ans);
	}
}

第8题:兰顿蚂蚁

兰顿蚂蚁,是于1986年,由克里斯·兰顿提出来的,属于细胞自动机的一种。

平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只“蚂蚁”。
蚂蚁的头部朝向为:上下左右其中一方。

蚂蚁的移动规则十分简单:
若蚂蚁在黑格,右转90度,将该格改为白格,并向前移一格;
若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。

规则虽然简单,蚂蚁的行为却十分复杂。刚刚开始时留下的路线都会有接近对称,像是会重复,但不论起始状态如何,蚂蚁经过漫长的混乱活动后,会开辟出一条规则的“高速公路”。

蚂蚁的路线是很难事先预测的。

你的任务是根据初始状态,用计算机模拟兰顿蚂蚁在第n步行走后所处的位置。

【数据格式】

输入数据的第一行是 m n 两个整数(3 < m, n < 100),表示正方形格子的行数和列数。
接下来是 m 行数据。
每行数据为 n 个被空格分开的数字。0 表示白格,1 表示黑格。

接下来是一行数据:x y s k, 其中x y为整数,表示蚂蚁所在行号和列号(行号从上到下增长,列号从左到右增长,都是从0开始编号)。s 是一个大写字母,表示蚂蚁头的朝向,我们约定:上下左右分别用:UDLR表示。k 表示蚂蚁走的步数。

输出数据为两个空格分开的整数 p q, 分别表示蚂蚁在k步后,所处格子的行号和列号。

例如, 输入:
5 6
0 0 0 0 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
2 3 L 5
程序应该输出:
1 3

再例如, 输入:
3 3
0 0 0
1 1 1
1 1 1
1 1 U 6
程序应该输出:
0 0

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

请严格按要求输出,不要画蛇添足地打印类似:“请您输入…” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
注意:不要使用package语句。不要使用jdk1.7及以上版本的特性。
注意:主类的名字必须是:Main,否则按无效代码处理。

在这里插入图片描述

import java.util.Scanner;

public class Main {
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int m = sc.nextInt();
		int n = sc.nextInt();
		int[][] g = new int[m][n];
		for(int i = 0;i < m;i++) {
			for(int j = 0;j < n;j++) {
				g[i][j] = sc.nextInt();
			}
		}
		int x = sc.nextInt();
		int y = sc.nextInt();
		String s = sc.next();
		int k = sc.nextInt();
		sc.close();
		
		int dir = getDir(s);//获取初始位置的方向
		int step = 0;
		while(true) {
			//若蚂蚁在黑格,右转90度,将该格改为白格,并向前移一格
			if(g[x][y] == 1) {
				dir = dir % 4 + 1;
				g[x][y] = 0;
			}else {//若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。
				dir--;
				if(dir == 0) dir = 4;
				g[x][y] = 1;
			}
			//前进一步
			if(dir == 1) x--;
			if(dir == 2) y++;
			if(dir == 3) x++;
			if(dir == 4) y--;
			step++;
			if(step == k) {
				System.out.println(x + " " + y);
				break;
			}
		}
	}
	public static int getDir(String s) {
		if(s.equals("U")) return 1; 
		if(s.equals("R")) return 2;
		if(s.equals("D")) return 3;
		if(s.equals("L")) return 4;
		return 0;
	}
}

——————————————————————————————————————————————————
第9题:斐波那契
在这里插入图片描述
在这里插入图片描述
——————————————————————————————————————————————————————
在这里插入图片描述

数据规模小的时候尽量用迭代,规模大的时候用矩阵
在这里插入图片描述

import java.math.BigInteger;
import java.util.Scanner;
/**
 * 1.由定义fib(n) = fib(n+2)-fib(n+1)
 * 2.由1得Σf(n) = f(n+2)-1;
 * 如果 m >= n + 2那么f(m) > Σf(n),结果是(f(n+2)-1)%p  ( f(m) 要比前面的和大很多,和f(m)取余就没意义了)
 * 否则 结果为(f(n+2)-1)%f(m)%p==f(n+2)%f(m)%p-1
 * @author 
 *
 */
public class Main {
	
	public static void main(String[] args) {
		// for (int i = 3; i <=10 ; i++) {
		//   System.out.println(fib(i).longValue());
		// }
		Scanner sc = new Scanner(System.in);
		long n, m, p;
		n = sc.nextLong();
		m = sc.nextLong();
		p = sc.nextLong();
		sc.close();
	
		BigInteger bigP = BigInteger.valueOf(p);
	
		if (m >= n + 2) {
			BigInteger ans = fib(n + 2, bigP);
			System.out.println(ans.mod(bigP).longValue() - 1);
		} else {
			BigInteger fibm = fib(m);
			BigInteger ans = fib(n + 2, fibm);
			System.out.println(ans.mod(fibm).mod(bigP).longValue() - 1);
		}
	}
	/*快速矩阵求fib*/
	private static BigInteger fib(long m) {
		BigInteger[][] ans = mPow(m - 2);
		return ans[0][0].add(ans[1][0]);
	}
	
	private static BigInteger fib(long m,BigInteger mod) {
		BigInteger[][] ans = mPow(m - 2,mod);
		return ans[0][0].add(ans[1][0]);
	}
	/*矩阵快速幂运算*/
	private static BigInteger[][] mPow(long n) {
		// a 是 1110 矩阵
		BigInteger[][] a =
					        {
					            {BigInteger.ONE, BigInteger.ONE},
					            {BigInteger.ONE, BigInteger.ZERO}
					        };
		//单元矩阵
		BigInteger[][] ans =
					        {
					            {BigInteger.ONE, BigInteger.ZERO},
					            {BigInteger.ZERO, BigInteger.ONE}
					        };
		while (n != 0) {
	    	if ((n & 1) == 1) {
		        //结果ans乘以当前平方
		        BigInteger t1 = ans[0][0];
		        BigInteger t2 = ans[1][0];
		        ans[0][0] = ans[0][0].multiply(a[0][0]).add(ans[0][1].multiply(a[1][0]));
		        ans[0][1] = t1.multiply(a[0][1]).add(ans[0][1].multiply(a[1][1]));
		        ans[1][0] = ans[1][0].multiply(a[0][0]).add(ans[1][1].multiply(a[1][0]));
		        ans[1][1] = t2.multiply(a[0][1]).add(ans[1][1].multiply(a[1][1]));
	    	}
	      	//对a进行平方
	    	BigInteger t1 = a[0][0];
	    	BigInteger t2 = a[1][0];
	    	BigInteger t3 = a[0][1];
	    	a[0][0] = a[0][0].multiply(a[0][0]).add(a[0][1].multiply(a[1][0]));
	    	a[0][1] = t1.multiply(a[0][1]).add(a[0][1].multiply(a[1][1]));
	    	a[1][0] = a[1][0].multiply(t1).add(a[1][1].multiply(a[1][0]));
	    	a[1][1] = t2.multiply(t3).add(a[1][1].multiply(a[1][1]));
	    	n >>= 1;
		}
		return ans;
	}
	
	private static BigInteger[][] mPow(long n,BigInteger mod) {
		BigInteger[][] a =
					        {
					            {BigInteger.ONE, BigInteger.ONE},
					            {BigInteger.ONE, BigInteger.ZERO}
					        };
	    //单元矩阵
	    BigInteger[][] ans =
					        {
					            {BigInteger.ONE, BigInteger.ZERO},
					            {BigInteger.ZERO, BigInteger.ONE}
					        };
	    while (n != 0) {
	    	if ((n & 1) == 1) {
	    		//结果乘以当前平方
		        BigInteger t1 = ans[0][0];
		        BigInteger t2 = ans[1][0];
		        ans[0][0] = ans[0][0].multiply(a[0][0]).add(ans[0][1].multiply(a[1][0])).mod(mod);
		        ans[0][1] = t1.multiply(a[0][1]).add(ans[0][1].multiply(a[1][1])).mod(mod);
		        ans[1][0] = ans[1][0].multiply(a[0][0]).add(ans[1][1].multiply(a[1][0])).mod(mod);
		        ans[1][1] = t2.multiply(a[0][1]).add(ans[1][1].multiply(a[1][1])).mod(mod);
		    }
	    	//进行平方
	    	BigInteger t1 = a[0][0];
	    	BigInteger t2 = a[1][0];
	    	BigInteger t3 = a[0][1];
	    	a[0][0] = a[0][0].multiply(a[0][0]).add(a[0][1].multiply(a[1][0])).mod(mod);
	    	a[0][1] = t1.multiply(a[0][1]).add(a[0][1].multiply(a[1][1])).mod(mod);
	    	a[1][0] = a[1][0].multiply(t1).add(a[1][1].multiply(a[1][0])).mod(mod);
	    	a[1][1] = t2.multiply(t3).add(a[1][1].multiply(a[1][1])).mod(mod);
	    	n >>= 1;
	    }
	    return ans;
	}
}

第10题:波动数列

观察这个数列:
1 3 0 2 -1 1 -2 …

这个数列中后一项总是比前一项增加2或者减少3。

栋栋对这种数列很好奇,他想知道长度为 n 和为 s 而且后一项总是比前一项增加a或者减少b的整数数列可能有多少种呢?

【数据格式】
输入的第一行包含四个整数 n s a b,含义如前面说述。
输出一行,包含一个整数,表示满足条件的方案数。由于这个数很大,请输出方案数除以100000007的余数。

例如,输入:
4 10 2 3
程序应该输出:
2

【样例说明】
这两个数列分别是2 4 1 3和7 4 1 -2。

【数据规模与约定】
对于10%的数据,1<=n<=5,0<=s<=5,1<=a,b<=5;
对于30%的数据,1<=n<=30,0<=s<=30,1<=a,b<=30;
对于50%的数据,1<=n<=50,0<=s<=50,1<=a,b<=50;
对于70%的数据,1<=n<=100,0<=s<=500,1<=a, b<=50;
对于100%的数据,1<=n<=1000,-1,000,000,000<=s<=1,000,000,000,1<=a, b<=1,000,000。

资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms
——————————————————————————————————————————————————————
设首项是 x,则有两种极端情况,全部 +a 或者 全部 -b 的情况,
x, x+a, x+2a, x+3a, x+(n-1)a ==> nx + (0 + 1 + 2 + … + n-1)a ==> nx + (n(n-1)/2)a = s —> x 的最小值 (一路相加等于 s ,所以是最小值)
x, x-b, x-2b, x-3b, x-(n-1)b ==> nx + (0 + 1 + 2 + … + n-1)b ==> nx + (n(n-1)/2)b = s —> x 的最大值 (一路相减等于 s ,所以是最大值)

解法1:枚举首项+深搜(能得20分)

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {
	
	private static int n;
	private static int s;
	private static int a;
	private static int b;
	private static final int MOD = 100000007;
	private static long ans;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
	    n = sc.nextInt();
	    s = sc.nextInt();
	    a = sc.nextInt();
	    b = sc.nextInt();
	    sc.close();

	    int x = 0;
	    //枚举首项
	    int min = (s - a * n * (n - 1) / 2) / n - 1;//为了确保能枚举到边界,可以扩大1
	    int max = (s + b * n * (n - 1) / 2) / n + 1;
	    for(x = min;x <= max;x++) {
	    	List<Integer> path = new ArrayList<>();
	    	path.add(x);
	    	dfs(x, 1, x, path);
	    }
	    System.out.println(ans);
	}
/**
 * 
 * @param x 上一项
 * @param cnt 截止到上一项已经有多少个
 * @param sum 截止到上一项已经求得的和
 */
	private static void dfs(int x, int cnt, int sum, List<Integer> path) {
		if(cnt == n) {
			if(sum == s) {
				ans++;
			//	for(int num : path) {  输出合理的路径
			//		System.out.print(num + " ");
			//	}
			//	System.out.println();
			} 
			if(sum > MOD) sum %= MOD;
			return ;
		}
		path.add(x + a);
		dfs(x + a, cnt + 1, sum + x + a, path);
		path.remove(path.size() - 1);
		
		path.add(x - b);
		dfs(x - b, cnt + 1, sum + x - b, path);
		path.remove(path.size() - 1);
	}	
}

最终解法:
转化为 01背包,用 dp 做

import java.util.Scanner;

public class Main {
	
	private static int n;
	private static long s;
	private static long a;
	private static long b;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
	    n = sc.nextInt();
	    s = sc.nextLong();
	    a = sc.nextLong();
	    b = sc.nextLong();
	    sc.close();

	    int t = n * (n - 1) / 2;

	    int[] dp = new int[t + 1];
	    dp[0] = 1;
	    for (int i = 1; i <= n - 1; i++) {
	    	for (int j = i * (i + 1) / 2; j >= i; j--) {
	    		// dp[j] += dp[j - i];
	    		// if (dp[j] > 100000007) dp[j] %= 100000007;
	    		dp[j] = (dp[j] + dp[j - i]) % 100000007;
	    	}
	    }
	    long ans = 0;
	    for (int i = 0; i <= t; i++) {
	    	if ((s - i * a + (t - i) * b) % n == 0)
	    		ans = (ans + dp[i]) % 100000007;
	    	// if (ans > 100000007) ans %= 100000007;
	    }
	    System.out.println(ans);
	}	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值