一、年齡問題
問題描述
美國數學家維納(N.Wiener)智力早熟,11 歲就上了大學。他曾在 1935~1936 年應
邀來中國清華大學講學。一次,他參加某個重要會議,年輕的臉孔引人注目。於是
有人詢問他的年齡,他回答說:“我年齡的立方是個 4 位數。我年齡的 4 次方是個
6 位數。這 10 個數字正好包含了從 0 到 9 這 10 個數字,每個都恰好出現 1 次。”
請你推算一下,他當時到底有多年輕。
解題思路
找好界限 “我年齡的立方是個 4 位數。我年齡的 4 次方是個
6 位數” 所以在 18和25 之間 當然 這道題碰巧答案就是 18
所以這道題着重看下在判斷一串數字 這 10 個數字正好包含了從 0 到 9 這 10 個數字,每個都恰好出現 1 次 是個技巧
public class Demo01_年齡問題 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
//如下代碼
String sum;
for(int i = 10; i<25; i++) {
sum = i*i*i +""+i*i*i*i;
int k = 0;
while(sum.lastIndexOf(sum.charAt(k)) == k) {
if(k==9) {
System.out.println(i);
return;
}
k++;
}
}
}
}
二、統計方形
問題描述
有一個n*m方格的棋盤,求其方格包含多少正方形、長方形
輸入格式
n,m規定m小於等於5000,n小於等於5000
輸出格式
方格包含多少正方形、長方形
輸入輸出樣例
輸入
2 3
輸出
8 10
解題思路
1.數據規模小於100時 用模擬法即可 也是枚舉的一個思想
import java.util.Scanner;
/**
*
* @author sjf666
*
* 2020年4月13日下午9:53:58
*/
//暴力 遍歷每個棋盤結點 在那之上 再進行不同邊長正方形、長方形的統計
public class Demo05_統計方形 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
int m =sc.nextInt();
int[][] map = new int[n][m];
long zsum = 0, csum= 0;
long sum = 0;
for(int i = 0; i< map.length; i++) {
for(int j = 0; j<map[i].length; j++) {
//正方形的統計
int d = 1;
while(i+d <= n && j+d <= m) {
zsum++;
d++;
}
//長方形的統計
int c = 1;
while(i+c <= n ) {
int k = 1;
while(j+k <= m) {
if(k != c)
csum++;
k++;
}
c++;
}
}
}
System.out.print(zsum+" "+csum);
}
}
2.數據規模大點 這是O(n^3) 當然會超時
所以 數學方法 降到 O(n^2)
import java.util.Scanner;
/**
*
* @author sjf666
*
* 2020年4月13日下午9:53:58
*/
public class Demo05_統計方形 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n =sc.nextInt();
int m =sc.nextInt();
int[][] map = new int[n][m];
long zsum = 0, csum= 0;
long sum = 0;
for(int i = 0; i< map.length; i++) {
for(int j = 0; j<map[i].length; j++) {
//數學果然。。
//sum 是所有矩形
//zsum是正方形的個數 ,csum = sum - zsum
sum+=(i+1)*(j+1);
zsum += Math.min(i+1, j+1);
}
}
csum = sum - zsum;
System.out.print(zsum+" "+csum);
}
}
三、火星人
問題描述
人類終於登上了火星的土地並且見到了神祕的火星人。人類和火星人都無法理解對方的語言,但是我們的科學家發明了一種用數字交流的方法。這種交流方法是這樣的,首先,火星人把一個非常大的數字告訴人類科學家,科學家破解這個數字的含義後,再把一個很小的數字加到這個大數上面,把結果告訴火星人,作爲人類的回答。
火星人用一種非常簡單的方式來表示數字――掰手指。火星人只有一隻手,但這隻手上有成千上萬的手指,這些手指排成一列,分別編號爲1,2,3…。火星人的任意兩根手指都能隨意交換位置,他們就是通過這方法計數的。
一個火星人用一個人類的手演示瞭如何用手指計數。如果把五根手指――拇指、食指、中指、無名指和小指分別編號爲1,2,3,4和5,當它們按正常順序排列時,形成了5位數12345,當你交換無名指和小指的位置時,會形成5位數12354,當你把五個手指的順序完全顛倒時,會形成54321,在所有能夠形成的120個5位數中,12345最小,它表示1;12354第二小,它表示2;54321最大,它表示120。下表展示了只有3根手指時能夠形成的6個3位數和它們代表的數字:
三進制數
123
132
213
231
312
321
代表的數字
1
2
3
4
5
6
現在你有幸成爲了第一個和火星人交流的地球人。一個火星人會讓你看他的手指,科學家會告訴你要加上去的很小的數。你的任務是,把火星人用手指表示的數與科學家告訴你的數相加,並根據相加的結果改變火星人手指的排列順序。輸入數據保證這個結果不會超出火星人手指能表示的範圍。
輸入格式
共三行。
第一行一個正整數N,表示火星人手指的數目(1≤N≤10000)。
第二行是一個正整數M,表示要加上去的小整數(1≤M≤100)。
下一行是1到N這N個整數的一個排列,用空格隔開,表示火星人手指的排列順序。
輸出格式
N個整數,表示改變後的火星人手指的排列順序。每兩個相鄰的數中間用一個空格分開,不能有多餘的空格。
解決思路
小白一個
此解法拿不到滿分 但是應對藍橋杯的題用此方法應該是可以的了
此題 是一個經典全排列的變形
首先我們要確定給出的火星人手指排列 在全排列的第幾層
然後 相加上那個小數
然後再找到 對應的層數的全排列 輸出即可
import java.util.Scanner;
/**
*
* @author sjf666
*
* 2020年4月14日下午3:02:03
*/
/*
*此題 是一個經典全排列的變形
*
*首先我們要確定給出的火星人手指 在全排列的第幾層 也就是找到這個手指
*然後 相加
*然後再找到 相加到的手指
*easy
*/
public class Demo07_火星人 {
static int N; //火星人的手指個數
static int M; //加上去的一個小數字
static int[] ans = new int[10000]; //存儲全排列的數組
static int[] book = new int[100001]; //標記數組
static int[] num1 = new int[10000]; //火星人原始的手指個數
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
M = sc.nextInt();
for(int i = 0; i < N; i++)
num1[i] = sc.nextInt();
dfs(0);
}
static int cnt = 1; //記錄每個全排列所表達的十進制數字
public static void dfs(int step) {
if(step == N) {
check();
cnt++;
return;
}
for(int i = 1; i <= N; i++) {
if(book[i] == 0) {
ans[step] = i;
book[i] = 1;
dfs(step+1);
book[i] = 0;
}
}
}
static int num2; //
public static void check() {
int i;
if(num2 == 0) {
for( i = 0; i < N; i++)
if(num1[i] != ans[i])
break;
if(i == N )
num2 = cnt+M;
}
else if(num2 == cnt)
for(int j = 0; j < N; j++)
if(j == N-1)
System.out.println(ans[j]);
else
System.out.print(ans[j]+" ");
}
}
四、帶分數
問題描述
100 可以表示爲帶分數的形式:100 = 3 + 69258 / 714
還可以表示爲:100 = 82 + 3546 / 197
注意特徵:帶分數中,數字1~9分別出現且只出現一次(不包含0)。
類似這樣的帶分數,100 有 11 種表示法。
題目要求:
從標準輸入讀入一個正整數N (N<1000*1000)
程序輸出該數字用數碼1~9不重複不遺漏地組成帶分數表示的全部種數。
注意:不要求輸出每個表示,只統計有多少表示法!
例如:
用戶輸入:
100
程序輸出:
11
再例如:
用戶輸入:
105
程序輸出:
6
資源約定:
峯值內存消耗(含虛擬機) < 64M
CPU消耗 < 3000ms
請嚴格按要求輸出,不要畫蛇添足地打印類似:“請您輸入…” 的多餘內容。
所有代碼放在同一個源文件中,調試通過後,拷貝提交該源碼。
注意:不要使用package語句。不要使用jdk1.6及以上版本的特性。
注意:主類的名字必須是:Main,否則按無效代碼處理。
解題思路
這是一個在 9 的全排列中放置 “ / ” 的問題
全排列是非常經典的了
所以解決的問題是 每當形成一個全排列時,我們還要根據題意來枚舉 第一個數的大小和“ / ” 的位置 所以用的枚舉思想 但每道題處理的還是有很大不同的
import java.util.Scanner;
/**
*
* @author sjf666
*
* 2020年4月13日下午3:46:03
*/
//根據題意 這是9的全排列然後通過枚舉 " / " 的位置來舉出符合題意的形式
public class Demo04_B2013_帶分數 {
static int[] fp = new int[9];
static int[] book = new int[10];
static int ans;
static int n;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
dfs(0);
System.out.println(ans);
}
//進行全排列
public static void dfs(int step) {
if(step == 9) {
if(check())
ans++;
return;
}
for(int i =1;i<=9;i++) {
if(book[i] == 0) {
fp[step] = i;
book[i] = 1;
dfs(step+1);
book[i] = 0;
}
}
}
public static boolean check() {
int t = n;
int numCnt = 0;
while(t != 0) {
numCnt++;
t/=10;
}
for(int i = 0; i < numCnt ; i++) {
int sum = 0 , sums = 1;
int temp = i;
while(temp>=0) {
sum+=fp[temp]*sums;
sums*=10;
temp--;
}
// " / "的位置
for(int j = i+4; j<9;j++) {
//計算
int fz=0,fm=0,fzs=1,fms=1;
for(int k = 8; k > i;k--) {
if(k <= j) {
fz+=fp[k]*fzs;
fzs*=10;
}
else {
fm+=fp[k]*fms;
fms*=10;
}
}
//整數
if(fz!=0 && fm!=0 && fz/fm == (float)fz/fm && fz/fm < n) {
if(sum+fz/fm == n)
return true;
}
}
}
return false;
}
}