E - Resistors in Parallel 最详细(

In this physics problem, what we are concerned about are only resistors. If you are poor at physics, do not worry, since solving this problem does not require you to have advanced abilities in physics.

Resistors are said to be connected together in parallel when both of their terminals are respectively connected to each terminal of the other resistors.

We have the following parallel resistor equation for k resistors with resistances R1, R2, …, Rk in parallel and their combined resistance R:

Now you have n resistors, the i-th of which has a resistance of ri ohms with the equation

You also have n selections, the i-th of which is a set of resistors Si such that

Please find a selection in which the resistors form a parallel resistor with the minimum resistance and output the reduced fraction of its resistance.

Input
The input contains several test cases, and the first line contains a positive integer T indicating the number of test cases which is up to 100.

For each test case, the only one line contains an integer n, where 1 ≤ n ≤ 10100.

Output
For each test case, output a line containing a reduced fraction of the form p/q indicating the minimum possible resistance, where p and q should be positive numbers that are coprime.

Example
Input
3
10
100
1000
Output
1/2
5/12
35/96

题目大意
给你n个电阻,第i个电阻的阻值是 如果i是某个平方数的倍数,就是正无穷(可以理解为没有这个电阻),否则就是i。然后有n个策略,第i个策略是选择i的约数的电阻。如第六个策略是拿1236的电阻,第八个策略是拿12的电阻(4 8 不存在)。

n种策略中寻找一个策略,使得这些电阻的阻值并联(倒数之和再倒数)最小。

首先,很轻松地判出不能暴力。
乍一看是一道数论的题,先找找有没有什么公式。我太菜了,放弃(
没办法,这道题只能打表找一下,下面是我的打表函数(输出是第几个策略 以及它的电阻值)

#include <iostream>
#include <bit/stsdc++.h>

using namespace std;
    vector<int>ve[100100];
bool judge(int n)
{
    for(int i=2;i*i<=n;i++)
        if(n%(i*i)==0)
            return false;
    return 1;
}
double fff(int g)
{
    int n=ve[g].size();
    double s=0;
    for(int i=0;i<n;i++)
        s+=(double)1/ve[g][i];
    return 1/s;
}
int main()
{
int flag;
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int f=i;
        for(int j=1;j<=f;j++)
        {
            if(i%j==0&&judge(j))
            ve[i].push_back(j);
        }
    }
    double s=0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    {
        double ret=fff(i);
        if(s>ret)
        {
            s=ret;
            flag=i;
        }
    }
    cout<<flag<<' '<<s<<endl;
    return 0;
}

可以看出,样例的值n是 6 30 210,那么这样有什么规律呢?

既然是数论,那么肯定离不了素数,那么我们就尽量往素数方面靠。可以看出,答案是前几个素数的乘积,确切一点说,是比n小的,从2开始的连续几个素数的乘积之中最大的那个(设为m)。

歪路
那么继续往下想,只要知道了这个数的所有因子再求个并联是不是就行了?那么接下来的问题就变成了如何求这个数的所有因子以及如何求所有数的并联了。

那么由分解素数(质因数分解)的知识,加上这道题分解素输的结果,可以知道他的因数一共有2^len个(len为素数个数),并且能够证明这个数不算很大,并且不会有不能用的电阻。那么感觉一切都顺理成章了……

但是!这样做的时间复杂度并不行,被窝队友分析出来还是可能会T,并且求并联也不好求,所以不行(所以是歪路)

于是我们只能继续找规律,现在看的主要是答案和len或者m有什么关系,比如说,知道通分的时候分子(已经取了倒数)必定是m,那么可以将它先通分为分子是m的,这样可以知道分母的关系了…

总之,结果是分子是前len个素数的乘积,分母是前len个素数+1的乘积

还有一个问题,这个题要用到大数,所以交给我队友写了…

素数可以打表,打的不多(别的地方没错,这个地方wa3你敢信?)

T=int(input())
arr=[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]
while T>0:
    T-=1
    s=int(input())
    q=1
    pos=0
    for i in range(len(arr)):
        if q*arr[i]>s:
            pos=i
            break
        else :
            q=q*arr[i]
    num1=1
    num2=1
    for i in range(pos):
        num1=num1*arr[i]
        num2=num2*(arr[i]+1)
    n=num1
    m=num2
    while(num1):
        t=num2%num1
        num2=num1
        num1=t
    n=n//num2
    m=m//num2
    print(n,end="")
    print("/",end="")
    print(m)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值