嘘~ 正在从服务器偷取页面 . . .


SP18202 HG - HUGE GCD 题解

题目链接:SP18202 HG - HUGE GCD

题意

保留 $9$ 位数字。 $1\le N,M \le 10^3,1 \le A_i, B_i \le 10^9$ 。

这个题很明显,我们只需要把两侧的数全都质因数分解,

然后扫一遍,每个质因数取两侧最小的值即可。比如左边有 $2^33^2$ ,右边有 $2^23^3$ ,那就取 $2^23^2$ 。

这样做的复杂度应该是 $\mathcal{O}(n \log^2 n + n \sqrt{M})$ ,其中 $M$ 为 $A_i,B_i$ 的值域。

不过这个做法需要对每个数都进行一次质因数分解,cxy 觉得这样很粗鲁,所以我们讲一种不需要分解的做法

我们依次考虑每个 $A_i$ ,然后枚举 $B_j$ 。记 $d = \gcd(A_i, B_j)$ ,然后令 $A_i,B_j$ 除以 $d$ ,答案乘上 $d$ 。

这样做的最坏时间复杂度是 $\mathcal{O}(n^2\log n)$ ,但是实际上运行的效果还是不错的,并且很优雅

代码:(来自参考文献[1])

#include<bits/stdc++.h>
#define up(l,r,i) for(int i=l,END##i=r;i<=END##i;++i)
#define dn(r,l,i) for(int i=r,END##i=l;i>=END##i;--i)
using namespace std;
typedef long long i64;
const int INF =2147483647;
int qread(){
    int w=1,c,ret;
    while((c=getchar())> '9'||c< '0') w=(c=='-'?-1:1); ret=c-'0';
    while((c=getchar())>='0'&&c<='9') ret=ret*10+c-'0';
    return ret*w;
}
const int MAXN =1e3+3;
const i64 MOD  =1e9;
int n,m,A[MAXN],B[MAXN]; i64 ans=1; bool f;
int gcd(int a,int b){return a?gcd(b%a,a):b;}
int main(){
    n=qread(); up(1,n,i) A[i]=qread();
    m=qread(); up(1,m,i) B[i]=qread();
    up(1,n,i) up(1,m,j){
        int d=gcd(A[i],B[j]); A[i]/=d,B[j]/=d;
        if((ans=ans*d)>=MOD) f=true; ans%=MOD;
    }
    if(f) printf("%09lld\n",ans); else printf("%lld\n",ans);
    return 0;
}

补充:

在C/C++的宏定义中,## 是一种称为“连接运算符”的特殊符号。它用于将两个标识符(包括宏参数)连接在一起形成一个新的标识符。

在上面的代码中,## 用于将 “END” 和参数 “i” 连接在一起,生成一个新的标识符。这在宏定义中很有用,因为它允许在每次宏调用时生成一个唯一的标识符。

具体来说,END##i 将会展开为一个新的标识符,其名称是由 “END” 和参数 “i” 连接而成。例如,如果宏调用是 up(1, 5, j),那么 ## 将会将 “END” 和 “j” 连接成一个新的标识符 “ENDj”。

这样做的目的是为了确保在多次调用宏函数时,每次都会生成一个不同的标识符,避免命名冲突和重复定义的问题。

需要注意的是,## 的使用有一些限制,它只能用于宏定义中,并且只能用于连接标识符。


参考文献

[1] https://www.luogu.com.cn/blog/over-knee-socks/solution-sp18202


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录