题意:给出n个数字,找出 ( i , j ) (i,j) (i,j)使得 l c m ( a i , a j ) lcm(a_i,a_j) lcm(ai,aj)最小
做法:假设现在有因子 p p p,这个序列中能整除p的有五个数 a 1 , a 2 , a 3 , a 4 , a 5 a_1,a_2,a_3,a_4,a_5 a1,a2,a3,a4,a5(从小到大排),从小到大枚举p的过程中有三种情况: (一): g c d ( a 1 , a 2 ) = k p > p gcd(a_1,a_2)=kp>p gcd(a1,a2)=kp>p,说明在因子 k p kp kp的情况讨论时会包含这种情况,就不用考虑了 (二): g c d ( a 1 , a 2 ) = p gcd(a_1,a_2)=p gcd(a1,a2)=p,此时 l c m ( a 1 , a 2 ) = a 1 ∗ a 2 / p lcm(a_1,a_2)=a_1*a_2/p lcm(a1,a2)=a1∗a2/p, 1:如果 g c d ( a i , a j ) = p 且 ( i , j ) ! = ( 1 , 2 ) gcd(a_i,a_j)=p且(i,j)!=(1,2) gcd(ai,aj)=p且(i,j)!=(1,2), a i ∗ a j / p > = a 1 ∗ a 2 / p a_i*a_j/p>=a_1*a_2/p ai∗aj/p>=a1∗a2/p,故后面的组合都不用考虑 2.如果 g c d ( a i , a j ) = k p > p gcd(a_i,a_j)=kp>p gcd(ai,aj)=kp>p,说明在因子 k p kp kp里面会包含这种情况,就不用考虑了 (三): a 1 = a 2 a_1=a_2 a1=a2,此时 l c m ( a 1 , a 2 ) = a 1 lcm(a_1,a_2)=a_1 lcm(a1,a2)=a1显然当前这个子情况中最优的
综上所述,在排除了所有相同数字的影响下,只要暴力枚举[1,maxn]所有p,如果有 n > = 2 n>=2 n>=2个数可以整除p,记录下前两个的lcm,和pos1,pos2,不断取最小的lcm即可
复杂度: O ( 2 ∗ 1 0 7 ∗ l o g ( 1 0 7 ) ) O(2*10^7*log(10^7)) O(2∗107∗log(107))
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<queue> #include<map> #define ll long long #define pb push_back #define rep(x,a,b) for (int x=a;x<=b;x++) #define repp(x,a,b) for (int x=a;x<b;x++) #define W(x) printf("%d\n",x) #define WW(x) printf("%lld\n",x) #define pi 3.14159265358979323846 #define mem(a,x) memset(a,x,sizeof a) #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r using namespace std; const int maxn=1e7+7; const int INF=1e9; const ll INFF=1e18; int a[maxn],n,val,x,id1,id2; int pos[maxn]; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} int main() { scanf("%d",&n); ll res=INFF; rep(i,1,n) { scanf("%d",&x); a[x]++; if (a[x]>1&&x<res)//如果出现相同的数字 //就把他们的情况取最优解 { res=x; id1=pos[x]; id2=i; } pos[x]=i; } for (ll i=1;i<maxn;i++) { val=0; bool mark=true; for (ll j=i;j<maxn;j+=i) { if (!a[j])continue; else if (a[j]!=0&&mark)//第一个整除i的数 { val=j; mark=false; } else//第二个整除i的数 { ll g=gcd(j/i,val/i); if (g==1) { ll lcm=j/i*val; //这么写可以防止爆范围 if (lcm<res) { res=lcm; id1=pos[val]; id2=pos[j]; } } break; //之前已经解释过,取前两个数字即可 } } } cout<<min(id1,id2)<<" "<<max(id1,id2)<<endl; return 0; }