天天看點

2019計蒜客藍橋杯A組模拟賽題解(Java)

填空題

  1. 求階乘位數

    這道題暴力…解決不了,可以使用通過對n!取10的對數來取n!的位數,判斷對數的位數是否大于等于10000,如果是輸出答案。

  • 公式

    l o g 10 ( n ! ) = l o g 10 ( 1 ∗ 2 ∗ 3 ∗ 4... ∗ n ) = l o g 10 ( 1 ) + l o g 10 ( 2 ) + . . . + l o g 10 ( n − 1 ) + l o g 10 ( n ) log10(n!)=log10(1*2*3*4...*n)=log10(1)+log10(2)+...+log10(n-1)+log10(n) log10(n!)=log10(1∗2∗3∗4...∗n)=log10(1)+log10(2)+...+log10(n−1)+log10(n)

  • 代碼
public class b1 {
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		double x=0;
		for(int i=1;;i++) {
			x+=Math.log10(i);
			if(x>=10000) {
				System.out.println(i);
				break;
			}
		}
	}
}
           
  1. 炮台實驗

    這一題讓我想到了高中的組合數學問題,有n個位置,不同的位置擺放不同的數,共有n!的排列。對于留存的炮台數的期望,可以對沒一個數留存下來的機率進行累加進而得到期望值。比如最大的數,無論放在哪,留存下的機率都為1。第二大的數,如果最大的數放在其前面會被摧毀,而放在後面不會被摧毀,是以留存的機率為 1 2 \frac{1}{2} 21​,最小的數除了放在第一個位置,其餘位置都會被摧毀,是以留存的機率為 1 n \frac{1}{n} n1​。是以要求的期望值為 1 + 1 2 + . . . + 1 n 1+\frac{1}{2}+...+\frac{1}{n} 1+21​+...+n1​,代入n=2019即可算出答案

  • 代碼
public class b2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		double c=0;
		double n=1;
		while(n<=2019) {
			c+=1/n;
			n++;
		}
		System.out.println(c);
	}
}
           
  1. 蒜頭國有 n 座城市,編号分别為 0,1,2,3,…,n−1。編号為 x 和 y 的兩座城市之間如果要修高速公路,必須花費 x∣y 個金币,其中|表示二進制按位或。 吝啬的國王想要花最少的價格修建高速公路,使得所有城市可以通過若幹條高速公路互相達到。現在請你求出 n=2019 時,一共有多少不同的方案,能讓所有城市連通并且造價最低。方案數可能很大,你隻需輸出對 10 9 +7 取模的結果。

思路

n座城市要實作互通,并且使得造價最低,屬于最小生成樹問題。

最小生成樹是需要在樹中構造n-1條邊使得n個結點都相連,不能有環。

這個問題中,可以将每個結點用二進制表示如,編号為13則二進制表示為1101。

而當把x和y這兩個城市連接配接時要使得花費金币數最少,即使得x|y等于x自身。

如編号為1101時,與0000,0001,0100,1000,1100,1001,0101,1101相連時會使得花費的金币數為1101。

即除了x上位數為1的位置可以為1或0時才能使得x|y=x。 是以可以計算1101這個編号中1的個數為3,是以可以選擇連接配接的城市有 2 3 − 1 2^3-1 23−1。

而對于n個城市,每個編号可以連接配接的城市為其二進制編碼中所含1的個數的序列排列數,是以可以編寫如下代碼:

package monisai1;

public class b4 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int n=2019;
		long ans=1;//0隻能和自己本身相連才不會使得金币數增加
		long mod=(long)1e9+7;
		for(int i=1;i<n;i++) {
			int t=0;
			for(int j=0;i>>j>0;j++) {
				if((i>>j&1)==1) {
					t++;
					//二進制枚舉, 
					//将i右移j位(且保證右移後的數大于0),将其與1按位與,結果為1則表示i對應二進制第j位上的數字為1
				}
			}
			ans=ans*((1<<t)-1)%mod; //1<<t 表示2^t 即将1左移t位
			//注意(1<<t)要哒括号 ,因為<<優先級小于-
		}
		System.out.println(ans);
	}

}

           

代碼填空題

1. 歐拉函數

  • 公式推導

    首先先看下對12求質因子的過程,可知 12 = 1 ∗ 2 ∗ 2 ∗ 3 = 2 2 ∗ 3 1 12=1*2*2*3=2^2*3^1 12=1∗2∗2∗3=22∗31

    通過歸納法我們可以證明出 n = p 1 k 1 ∗ p 2 k 2 ∗ . . . p j k j n=p_1^{k1}*p_2^{k2}*...p_j^{kj} n=p1k1​∗p2k2​∗...pjkj​( p i p_i pi​為n的質因子)

    而 φ ( n ) = ∏ i = 1 j p i k i \varphi(n)=\prod_{i=1}^jp_i^{ki} φ(n)=∏i=1j​piki​

    = p 1 k 1 ∗ ( ( p 1 − 1 ) / p 1 ) ∗ p 2 k 2 ∗ ( ( p 2 − 1 ) / p 2 ) ∗ . . . p j k j ∗ ( ( p j − 1 ) / p j ) =p_1^{k1}*((p_1-1)/p_1)*p_2^{k2}*((p2-1)/p2)*...p_j^{kj}*((p_j-1)/p_j) =p1k1​∗((p1​−1)/p1​)∗p2k2​∗((p2−1)/p2)∗...pjkj​∗((pj​−1)/pj​)

    = p 1 k 1 ∗ p 2 k 2 ∗ . . . p j k j ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ . . . ∗ ( 1 − 1 p j ) =p_1^{k1}*p_2^{k2}*...p_j^{kj}*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})*...*(1-\frac{1}{p_j}) =p1k1​∗p2k2​∗...pjkj​∗(1−p1​1​)∗(1−p2​1​)∗...∗(1−pj​1​)

    = n ∗ ( 1 − 1 p 1 ) ∗ ( 1 − 1 p 2 ) ∗ . . . ∗ ( 1 − 1 p j ) =n*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})*...*(1-\frac{1}{p_j}) =n∗(1−p1​1​)∗(1−p2​1​)∗...∗(1−pj​1​)

  • 代碼
import java.util.*;

public class Main {
    public static int euler(int n) {
        int res = n;
        for (int i = 2; i <= n; i++) {
            if (n % i == 0) {
                res = res-res/i ;
                while (n % i == 0) {
                    n /= i;
                }
            }
        }
        return res;
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        System.out.println(euler(n));
    }
}
           

程式設計

  1. 掎角之勢
package monisai1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class c1_answer {

	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub

		int N;
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		N=Integer.parseInt(br.readLine());
		while(N--!=0){
			StringTokenizer token=new StringTokenizer(br.readLine());
			int x1=Integer.parseInt(token.nextToken());
			int y1=Integer.parseInt(token.nextToken());
			int x2=Integer.parseInt(token.nextToken());
			int y2=Integer.parseInt(token.nextToken());
			int x3=Integer.parseInt(token.nextToken());
			int y3=Integer.parseInt(token.nextToken());
		      
			
			//假設三點為A、B、C
			x1 -= x3; 
	        y1 -= y3;
	        x2 -= x3;
	        y2 -= y3;
			//計算兩條邊向量AC(x1,y1)BC (x2,y2)
			if(x1*y2==x2*y1) { //叉乘公式 S=1/2*BA*BC=1/2*(x1*y2-x2*y1) 如果三角形面積為0則表明解不存在
				System.out.println("NO SOLUSTION");
				continue;
			}
			double s=Math.abs(x1*y2-x2*y1);  //三角形ABC面積的一半
			double a=Math.sqrt(x1*x1+y1*y1);
			double b=Math.sqrt(x2*x2+y2*y2);
			x1-=x2;
			y1-=y2;
			double c = Math.sqrt(x1 *x1  + y1  *y1);
			  //計算AB的距離  注意未避免c計算錯誤  在之前計算AC BC向量時要A,B的坐标要減去同一個點的坐标
			double r1=s/(a+b+c); //内接圓半徑公式 
			double r2=a*b*c/s/2;// 外接圓半徑公式
			System.out.println(String.format("%.10f", Math.acos(-1)*r1*r1)+" "+String.format("%.10f", Math.acos(-1)*r2*r2));
		}
		System.out.println(Integer.MAX_VALUE);
		System.out.println(Long.MAX_VALUE);
	}

}

           
  1. 輕重搭配
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {

	static int []a=new int[500010];
	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		int N=Integer.parseInt(br.readLine());
		StringTokenizer token=new StringTokenizer(br.readLine());
		for(int i=0;i<N;i++) {
			a[i]=Integer.parseInt(token.nextToken());
		}
		Arrays.sort(a, 0,N);
	
		int ans=N;
		int j=N/2;
		for(int i=0;i<N/2;i++) {
			while(j<N&&a[j]<2*a[i]) j++;
			if(j==N) break;
			ans--;
			j++;
		}
		System.out.println(ans);
	}
}
           

貪心算法,初始票設定為n,兩兩配對,從數組中的0号位置開始和n/2位置後的資料開始比較,如果符合超出a[i]兩倍的條件就開始配對,配對成功就将購票數減一。接着繼續往下配對,直至pos到達終點。