填空题
- 求阶乘位数
这道题暴力…解决不了,可以使用通过对n!取10的对数来取n!的位数,判断对数的位数是否大于等于10000,如果是输出答案。
- 公式
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)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;
}
}
}
}
- 炮台实验
这一题让我想到了高中的组合数学问题,有n个位置,不同的位置摆放不同的数,共有n!的排列。对于留存的炮台数的期望,可以对没一个数留存下来的概率进行累加从而得到期望值。比如最大的数,无论放在哪,留存下的概率都为1。第二大的数,如果最大的数放在其前面会被摧毁,而放在后面不会被摧毁,所以留存的概率为12\frac{1}{2}21,最小的数除了放在第一个位置,其余位置都会被摧毁,所以留存的概率为1n\frac{1}{n}n1。所以要求的期望值为1+12+...+1n1+\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);
}
}
- 蒜头国有 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,所以可以选择连接的城市有23−12^3-123−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=22∗3112=1*2*2*3=2^2*3^112=1∗2∗2∗3=22∗31
通过归纳法我们可以证明出n=p1k1∗p2k2∗...pjkjn=p_1^{k1}*p_2^{k2}*...p_j^{kj}n=p1k1∗p2k2∗...pjkj(pip_ipi为n的质因子)
而φ(n)=∏i=1jpiki\varphi(n)=\prod_{i=1}^jp_i^{ki}φ(n)=∏i=1jpiki
=p1k1∗((p1−1)/p1)∗p2k2∗((p2−1)/p2)∗...pjkj∗((pj−1)/pj)=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)
=p1k1∗p2k2∗...pjkj∗(1−1p1)∗(1−1p2)∗...∗(1−1pj)=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−p11)∗(1−p21)∗...∗(1−pj1)
=n∗(1−1p1)∗(1−1p2)∗...∗(1−1pj)=n*(1-\frac{1}{p_1})*(1-\frac{1}{p_2})*...*(1-\frac{1}{p_j})=n∗(1−p11)∗(1−p21)∗...∗(1−pj1) - 代码
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));
}
}
程序设计
- 掎角之势
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);
}
}
- 轻重搭配
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到达终点。
本文探讨了多种算法挑战,包括求阶乘位数、炮台实验、蒜头国高速公路建设、欧拉函数计算及复杂几何问题。通过编程解决实际问题,展示了数学与算法在信息技术领域的应用。
556

被折叠的 条评论
为什么被折叠?



