传送门
开始傻了…以为分解质因子之后无脑去抵消就好了,其实不是
比如10 10 4
一开始应该先消成2 2 4,然后可以消成1 1 1
这样是最优的
然后考虑怎么才是最优的,由于素因子各自独立所以可以分开考虑
显然最后素因子会集中在某个数上,否则还可以互相抵消
那我们需要让这个数的素因子最小,也就是每次挑素因子幂最大的去抵消
而且每次取出最大的两个,也不是完全抵消,而是只抵消一次保证最优解。
这样可以使用优先队列来解决。
但是有更快的方法
设这种质因子幂和为 s u m sum sum,最大的幂为 m a x x maxx maxx
当 m a x x ∗ 2 > = s u m maxx*2>=sum maxx∗2>=sum时,一定是剩下 2 ∗ m a x x − s u m 2*maxx-sum 2∗maxx−sum个
否则,一定可以消耗成 0 0 0个或者 1 1 1个
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e5+10;
const int N = 1e8;
const int mod = 1e9+7;
int a[maxn],prime[maxn],top,n;
bool vis[N];
void make_prime(int inf)
{
for(int i=2;i<=inf;i++)
{
if( !vis[i] ) prime[++top] = i;
for(int j=1;j<=top&&prime[j]*i<=inf;j++)
{
vis[i*prime[j]] = 1;
if( i%prime[j]==0 ) break;
}
}
}
int quick(int x,int n)
{
int ans = 1;
for( ; n ; n>>=1,x=x*x%mod )
if( n&1 ) ans = ans*x%mod;
return ans;
}
priority_queue<int,vector<int>,less<int> >q;
signed main()
{
make_prime(1e4);
int t; cin >> t;
while( t-- )
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
int ans = 1;
for(int i=1;i<=top;i++)
{
for(int j=1;j<=n;j++)
{
int num = 0;
while( a[j]%prime[i]==0 )
a[j]/=prime[i],num++;
if( num!=0 ) q.push(num);
}
while( q.size()>1 )
{
int u = q.top(); q.pop();
int v = q.top(); q.pop();
u--,v--;
if( u ) q.push( u );
if( v ) q.push( v );
}
if( !q.empty() )
{
int u = q.top(); q.pop();
ans = ans*quick( prime[i],u )%mod;
}
}
sort( a+1,a+1+n ); a[n+1] = 0;
for(int i=1;i<=n;i++)
{
if( a[i]==1 ) continue;
else if( a[i]==a[i+1] ) i++;//消除了
else ans = ans*a[i]%mod;
}
cout << ans << endl;
}
}