E - Resistors in Parallel

Resistors in Parallel - Gym 102028E - Virtual Judge (vjudge.net)

题意:

给定n个电阻,第i个电阻的阻值是i,如果i是平方数的倍数,那么阻值是正无穷大。有n个选电阻的策略,第i个策略是选择所有i的因子的电阻。从这n个策略中寻找一个策略,让拿得的电阻并联阻值最小。

首先,阻值无穷大的电阻取倒数后为0,可以看做没有这个电阻。而且可以看出n越大,能选的策略数就越多,最佳电阻就越小,后面更多的策略数对应的最小电阻肯定是小于等于前面策略数能选出的最小电阻的。所以我们选的最佳策略数是随着n增大而增大的。而且应该满足某种关系,所以考虑打表找规律。

对于每个n暴力dfs全部情况跑一遍取电阻最小的策略选法。可以看到规律如下:

第一个数字是n,第二个数字是选择的策略数,第三个数字是对应的电阻。我只打印了有策略数有变化的n。
将n从1枚举到2500,可以发现从策略数的变化是1 2 6 30 210 2310,这有什么规律呢?其实不难看出除1外这些数字都是前几个素数的乘积,并且这个乘积小于等于n,因为毕竟策略数本身就是前n个中数选的。

知道了对于n我们选哪个策略最优,那么我们如何得出答案?对这些最优策略数进行因子分解可以发现。这些最优策略都没有平方数的倍数,也就是不需要考虑正无穷大的电阻,因为最优选法里根本没有。可以猜测答案的的分子和分母也一定满足某种规律。

我们从样例给的三个答案下手。

第一个样例n==10,我们选择的是第6个策略,6的因子是1, 2, 3, 6。我们对他们取倒数相加之后再取倒数的结果,可以看做对下面先通分相加再取到数。也就是分子一定是6,那么分母就是12。同理第二个样例n==100选的是第30个策略,分子一定是30,分母就是72。第三个样例n==1000选的是210,分子是210,分母是576。

可以发现分子就是策略数本身,也就是总乘积小于等于n的前几个素数。那么分母有什么规律呢?首先可以看到72=12*6,576=72*8,那么下一个答案的分母是不是576*10呢?即2310/5760?我们发现这个数等于0.401,对不上打表得到的0.334。所以考虑另外的规律:既然分子是前几个素数的乘积,那么我们考虑对分母也进行乘积分解看看能不能对得上分子的乘积规律,可以发现如下:

6=2*3, 12=3*4 ;30 = 2*3*5,  72=3*4*6; 210=2*3*5*7, 576=3*4*6*8; 

发现分母满足分子每个素数+1的乘积。把这个规律带入2310可以得到分母是6912,除一下发现刚好是0.334。这样可以确定答案了:

分子是乘积小于等于n的前几个素数,分母是这些素数+1的乘积

n最大是10^100,因为答案是素数乘积,其实很快就能乘爆这个数,我们打印前1000个素数肯定够用了,因为涉及到大数运算,用python更加方便。

附上代码:
 

def gcd(x, y):
    while y:
        x, y = y, x % y
    return x

def cal(s, primes):
    q = 1
    num1, num2 = 1, 1

    for i, prime in enumerate(primes):
        if q * prime > s:
            break
        q *= prime
        num1 *= prime
        num2 *= (prime + 1)

    gcd_value = gcd(num1, num2)
    return num1 // gcd_value, num2 // gcd_value

def main():
    primes = [
        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, 271, 277, 281, 283, 293, 307,
        311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421,
        431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
        557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
        661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797,
        809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929,
        937, 941, 947, 953, 967, 971, 977, 983, 991, 997
    ]
    T = int(input())
    for _ in range(T):
        s = int(input())
        n, m = cal(s, primes)
        print(f"{n}/{m}")

if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值