社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
数学知识的运用
1)并非数学竞赛
2)进制问题及其巧妙运用
3)整数与整除问题
4)欧几里得扩展定理
5)有理数表示,大数问题
例1【奇怪的捐赠】
地产大亨Q先生临终的遗愿是:拿出100万元给X社区的居民抽奖,以稍慰藉心中愧疚。
麻烦的是,他有个很奇怪的要求:
1. 100万元必须被正好分成若干份(不能剩余)。
每份必须是7的若干次方元。
比如:1元, 7元,49元,343元,...
2. 相同金额的份数不能超过5份。
3. 在满足上述要求的情况下,分成的份数越多越好!
请你帮忙计算一下,最多可以分为多少份?
public static void main(String[] args) {
//进制问题,将十进制转换为七进制
String s = Integer.toString(100*100,7);
System.out.println(s);//41104
int sum = 0;
for(int i = 0;i < s.length();i++){
sum+=s.charAt(i)-'0';
}
System.out.println(sum);//10
}
}
例2【天平称重】
用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
如果只有5个砝码,重量分别是1,3,9,27,81
则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1
要求程序输出的组合总是大数在前小数在后。
可以假设用户的输入的数字符合范围1~121。
方法一(递归法):当x>权重/2时,需要动用大一点的数来减去
public class Main {
public static String f(int x){
int a = 1;
while(a<x)
a = a*3;
if(a == x) return ""+x;
//用前一级来+
else if (x <= a/2) return a/3 + "+" + f(x-a/3);
else return a + "-" + reverse(f(a-x));
}
//正负变号
public static String reverse(String s){
s = s.replace('+','#');
s = s.replace('-','+');
s = s.replace('#','-');
return s;
}
public static void main(String[] args) {
for(int i=1;i<50;i++){
System.out.println(i+":"+f(i));
}
}
}
方法二(进制法):
//天平称重,进制解法
public class Main {
public static String f(int x){
String s = "";
int a = 1;//权重
while(x > 0){
int sh = x / 3;//商
if(x%3 == 1){
s = "+" + a + s;
}
else if(x%3 == 2){
s = "-" + a + s;
sh++;
}
a = a*3;
x = sh;
}
return s.substring(1);
}
public static void main(String[] args) {
for(int i=1;i<50;i++){
System.out.println(i+":"+f(i));
}
}
}
例3【Excel地址】
Excel单元格的地址表示很有趣,它使用字母来表示列号,比如:
A表示第1列,
B表示第2列,
Z表示第26列,
AA表示第27列,
AB表示第28列,
BA表示第53列,
....
当然Excel的最大列号是有限度的,所以转换起来不难。
如果我们想把这种表示法一般化,可以把很大的数字转换为很长的字母序列呢?
本题目既是要求对输入的数字, 输出其对应的Excel地址表示方式。
例如,
输入:
26
则程序应该输出:
Z
再例如,
输入:
2054
则程序应该输出:
BZZ
我们约定,输入的整数范围[1,2147483647]
解析:该题并不属于26进制类型,A是从1开始而不是从0开始,正确方式应该是利用暴力破解的逆向思维
例4【日期问题】
问题描述 已知2011年11月11日是星期五,问YYYY年MM月DD日是星期几?注意考虑闰年的情况。尤其是逢百年不闰,逢400年闰的情况。 输入格式 输入只有一行 YYYY MM DD 输出格式 输出只有一行 W 数据规模和约定 1599 <= YYYY <= 2999 1 <= MM <= 12 1 <= DD <= 31,且确保测试样例中YYYY年MM月DD日是一个合理日期 1 <= W <= 7,分别代表周一到周日 样例输入 2011 11 11 样例输出 5
解析:A-B = A - 基准 - (B - 基准)
public class Main {
public static void main(String[] args) {
int w=5;
Scanner sc=new Scanner(System.in);
String []data=new String[3];
data=sc.nextLine().split(" ");
int year=Integer.parseInt(data[0]);
int month=Integer.parseInt(data[1]);
int date=Integer.parseInt(data[2]);
int x=f(year,month,date)-f(2011,11,11);
switch(x%7) {
case 0:w=5;break;
case 1:w=6;break;
case 2:w=7;break;
case 3:w=1;break;
case 4:w=2;break;
case 5:w=3;break;
case 6:w=4;break;
case -1:w=4;break;
case -2:w=3;break;
case -3:w=2;break;
case -4:w=1;break;
case -5:w=7;break;
case -6:w=6;break;
}
System.out.println(w);
}
static Boolean is_leap_year(int n) {
if((n%4==0&&n%100!=0)||n%400==0)
return true;
return false;
}
static int f(int year, int month, int date) {
int [] m = {0,31,28,31,30,31,30,31,31,30,31,30,31};//易错 :月份从一开始,前面0不可省
if(is_leap_year(year))
m[2]++;//易错
int sum=0;
for(int i=1599;i<year;i++) {
sum+=365;
if(is_leap_year(i))
sum=sum+1;
}
for(int i=1;i<month;i++) {
sum+=m[i];
}
sum=sum+date;
return sum;
}
}
例5【模m运算】
有3堆硬币,分别是3,4,5
二人轮流取硬币。
每人每次只能从某一堆上取任意数量。
不能弃权。
取到最后一枚硬币的为赢家。
求先取硬币一方有无必胜的招法。
解析:模2的加法(同余理论):1+1=0, 1+0=1, 0+1=1, 0+0=0
理论:如果和为0,无论怎么拿,都会!=0;如果非0,总有办法...0
若将局面变成1 4 5,模2加为0,那么留给对方的必为输局
//尼姆堆的模2加(异或)解法
public class Main {
static void f(int []a){
int sum = 0;
for(int i=0;i<a.length;i++){
sum^=a[i];
}
if(sum==0) {
System.out.println("输局");
return;
}
//x ^ y ^y = x
for(int i=0;i<a.length;i++){
int x = sum ^a[i];
if(x < a[i])//拿了之后数量一定比之前少!!!
System.out.println(a[i] + "-->" + x);
/* 5-->0
12-->9
14-->11*/
}
}
public static void main(String[] args) {
int [] a = {2,5,12,14};
f(a);
}
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!