大致题意:当 i 是平方数(平方根大于二)的整数倍时, = ,相当于断路,否则 =i 。
是电阻的集合,当 j 是 i 的因数时 (包括 和)。
给出 n 代表前 n 个集合,选出 n 个集合中的电阻并联结果最小的那个集合,输出并联电阻。
容易发现最后的结果是关于n的阶梯型函数f(n).
n=1 时 f(1)=1;
n [2,6) 时 f(n) = 2/3;
n [6,30) 时 f(n) = 1/2;
n [30,210) 时 f(n) = 5/12;
······
规律就是,前 i 个素数的前缀积MUL为f(n)的第 i 个跳跃间断点。
并联越多小电阻,总电阻越小,那就从最小的电阻开始选,越多越好。因为平方数下标的电阻断路,所以每个质因子只用考虑一次。能选第 i 个素数时,n 应该不小于前 i 个素数的乘积,这样才能保证前 i 个素数在前 i 个集合中同时出现在某一个集合内。
选出包含前 i 个素数的集合之后,发现该集合内的电阻包括 该 i 个素数 和 该 i 个素数所有组合出的乘积。硬求肯定爆炸了。
设已经求出的电阻倒数之和为sum,下一个素数为p。则加入下一个电阻时有 sum = sum*(1+1/p),这样就可以很顺利的求出最终结果的倒数。因为要输出成分数形式,所以在递推的过程要分别保存分子和分母,最后输出前记得约分。
前 i 个素数的前缀积在 i 不到60时就超过了,而 t 不超过100,可以打表前60个素数之后每次重新递推。
import java.util.*;
import java.math.*;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
BigInteger num_1 = new BigInteger("1");
BigInteger num_2 = new BigInteger("2");
BigInteger num_3 = new BigInteger("3");
BigInteger num_0 = new BigInteger("0");
BigInteger fz,fm;
BigInteger sum;
BigInteger now;
int[] prime = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269};
int t,i;
String S;
t = input.nextInt();
S = input.nextLine();
while(t-- > 0) {
i = 0;
fz = new BigInteger("1");
fm = new BigInteger("1");
sum = new BigInteger("1");
S = input.nextLine();
now = new BigInteger(S);
while(now.compareTo(sum.multiply(new BigInteger(String.valueOf(prime[i])))) >= 0) {
BigInteger temp = new BigInteger(String.valueOf(prime[i++]));
sum = sum.multiply(temp);
fz = fz.multiply(temp.add(num_1));
fm = fm.multiply(temp);
temp = fz.gcd(fm);
if(temp.compareTo(num_1)!=0) {
fz = fz.divide(temp);
fm = fm.divide(temp);
}
}
System.out.println("" + fm + "/" + fz);
}
}
}
C++没存大数模板,就算有也感觉很难敲,不如直接用JAVA的大数,队伍打算以后遇到大数就用JAVA写。但是JAVA大数又用得很少,不熟悉。那就顺便总结一下吧。
部分转载于:https://blog.csdn.net/reigns_/article/details/81672069
对大整数来说,用BigInteger:
1.读入:
//从开始读到文件尾
Scanner cin = new Scanner(System.in); //相当于C++中的cin,只不过这个cin需要自己创建
while(cin.hasNext()){ //等同于!=EOF
BigInteger a;
a = cin.nextBigInteger(); //读入一个BigInteger;
System.out.println(a); //输出a并换行
}
//T组样例:
Scanner cin = new Scanner(System.in);
int T = cin.nextInt();
while (T-- > 0) {
BigInteger a,b;
a = cin.nextBigInteger(); //读入一个BigInteger;
b = cin.nextBigInteger(); //读入一个BigInteger;
}
2.构造:
BigInteger a=new BigInteger(“123”); //第一种,参数是字符串
String S;
···
BigInteger a=new BigInteger(S); //第一种,参数是字符串
BigInteger a=BigInteger.valueOf(123); //第二种,参数可以是int、long
3.常数:(之前不会,还自己构造。。)
BigInteger.ZERO //大整数0
BigInteger.ONE //大整数1
BigInteger.TEN //大整数10
4.常用方法:
//加
a = a.add(b); // a += b
//减
a = a.subtract(b); // a -= b
//乘
a = a.divide(b); // a /= b
//除
a = a.multiply(b); // a *= b
//取模
a = a.mod(b); //a %= b;
a = a.remainder(b); //a %= b;
//指数
a = a.pow(b); // a = a^b(a的b次方,不是取异或)
//gcd
a = a.gcd(b); // a = gcd(a,b);
//abs
a = a.abs(); //取绝对值
//比较
a.compareTo(b) //a小于b返回-1,等于返回0,大于返回1
a.equals(b) //返回真假逻辑值
--------------//例子: n.compareTo(BigInteger.ZERO)==0 //相当于n==0
--------------//例子: n.equals(BigInteger.ZERO) //结果是逻辑值
//取最大、最小
a = a.max(b); //求最大值 a = max(a,b)
a = a.min(b); //求最小值 a = min(a,b)
//求大整数位数
len = a.toString().length(); //a的类型为BigInteger
对大精度小数来说,用BigDecimal:
与BigInteger大致相同,在读入和构造的时候主要通过字符串类转化过去,或者用valueOf方法。
加减乘的方法签名相同。至于除法就有些不一样了:
https://www.jianshu.com/p/881afd68316e
https://www.jianshu.com/p/2947868d76eb
public BigDecimal divide (BigDecimal value,int scale,RoundingMode mode);
divide方法可以只有第一个参数,但是只有第一个参数时,如果结果是无限小数则会抛出异常,所以要设置第二个参数(
表示小数位数)和第三个参数(表示取舍方式,一般用 BigDecimal.ROUND_HALF_UP 或者 BigDecimal.ROUND_CEILING即四舍五入)
不能只设置前两个参数。
还有一个直接设置精度的方法:
public BigDecimal setScale(int scale, RoundingMode roundingMode)
两个参数都不能省。