P2651 添加括号III 题解
作者:互联网
或许是我太蒟了,想了好久的解法。
此题很明确,我们需要加上若干括号使得最后结果为整数。
明显的,我们在日常的数学计算中,可以发现:设任意分数 \(\dfrac{x}{y}\) ( \(x\) , \(y\) 均为正整数),如果 \(\gcd(x,y)=y\) ,那么 \(\dfrac{x}{y}=x\) ,也就是 \(\dfrac{x}{y}\) 为整数,即 \(x\) , \(y\) 可以约分。
这句话是解题的关键。理解这句话之后,我们只需要了解哪些数是分子,哪些数是分母即可判断。
分析可得, \(a_1\) 只能是分子, \(a_2\) 只能是分母,剩余的数可以是分子,也可以是分母。(证明见文末)
为了尽可能使 \(a_2\) 被约分,最优解法就是:将剩余的数和 \(a_1\) 全部处于分子处,分母处只留 \(a_2\) 。
这样,我们只需要判断约分之后 \(a_2\)是否为1。
如何约分呢?将分子的数不断与 \(a_2\) 求最大公约数(设为 \(z\) ),那么 \(a_2\) 与这个数就能约去 \(z\) ,令 \(a_2 \gets \dfrac{a_2}{z}\),就可以实现最大化约分。
思路分析完毕。代码实现如下:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
typedef long long LL;
int t,n;
LL a[MAXN];
LL gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
{
if(i==2) continue;//特别注意过滤a2!!!
a[2]=a[2]/gcd(a[2],a[i]);//约分
}
if(a[2]==1) printf("Yes\n");
else printf("No\n");
}
return 0;
}
关于前文的证明(有点粗略,请见谅):
首先,设存在 长度为 \(n\) 的序列 \(b_1,b_2,...,b_n\) ,令 \(r=b_1/b_2/b_3/.../b_n\) ,那么根据 \(\dfrac{a}{\frac{b}{c}}=\dfrac{a \times c}{b}\) ,可以得到如下结论:
- 如果 \(n\) 是偶数,\(r=\dfrac{b_1 \times b_3 \times ... \times b_{n-1}}{b_2 \times b_4 \times ... \times b_n}\)。
- 如果 \(n\) 是奇数,\(r=\dfrac{b_1 \times b_3 \times ... \times b_n}{b_2 \times b_4 \times ... \times b_{n-1}}\)。
所以对于这个序列中的 \(b_i\) (\(1 \leq i \leq n\)),如果 \(i\) 是奇数, \(b_i\) 处于分子处,如果 \(i\) 是偶数, \(b_i\) 处于分母处。
对于这道题中的 \(a\) 序列,我们虽然可以通过添加括号,使得 \(a_i\) (\(3 \leq i \leq n\))的位置改变,位于分母还是分子具有不确定性,但是无论如何, \(a_1\) 永远是第 1 位, \(a_2\) 永远是第 2 位,那么 \(a_1\) 只能处于分子处, \(a_2\) 只能处于分母处。
标签:...,dfrac,LL,times,约分,题解,P2651,III,分母 来源: https://www.cnblogs.com/Plozia/p/16109629.html