大致题意: 乱序给出(k)个数两两(gcd)和(lcm),让你求出这(k)个数。
前言
比赛时看到这题心想神仙题,然后发现(2le kle4)。。。
于是又想快一个小时,才差不多想到了正解。
结果写完之后少加了一句检验,就被卡掉(2)分,只剩(98)了(2333)。
(k=2)
(k=2)应该是比较简单的,考虑到保证有解,因此直接把给出的数输出即可。
(k=3)
(k=3)的情况略微复杂。
考虑到乱序不太好做,一个很直接的想法,我们全排列来枚举对应顺序。
则最后可以得到:
[gcd(v_1,v_2),gcd(v_1,v_3),gcd(v_2,v_3)
]
[lcm(v_1,v_2),lcm(v_1,v_3),lcm(v_2,v_3)
]
然后如果你知道一个很显然的性质,那么这题就很水了:
[xcdot y=gcd(x,y)cdot lcm(x,y)
]
也就是说,我们可以将上面的式子两两相乘得到(v_1cdot v_2,v_1cdot v_3,v_2cdot v_3)的值。(注意相乘会爆(long long),因此需要开(\_\_int128))
然后,如果我们求出(v_1cdot v_2,v_1cdot v_3)的(gcd),则它就相当于是(v_1cdot gcd(v_2,v_3))。
因此,我们用(gcd(v_1cdot v_2,v_1cdot v_3))去除以(gcd(v_2,v_3)),就得到了(v_1)的值!
而(v_2)和(v_3)既然已知与(v_1)的乘积,就可以直接通过除法算出。
注意在枚举到的一种排列中,有许多无解的情况需要特判,列举如下:
- 两个数对应的(lcm)不能整除这两个数对应的(gcd)。
- (gcd(v_1cdot v_2,v_1cdot v_3))不能整除(gcd(v_2,v_3))。
- 最后算出的(v_2cdot v_3)不等于(gcd(v_2,v_3)*lcm(v_2,v_3))。
- 最后算出的(gcd(v_1,v_2),gcd(v_1,v_3),gcd(v_2,v_3))与已知数据不符(我就是少判了这个丢了(2)分)。
(k=4)
知道了(k=3),(k=4)其实只要在此基础上加一些细节就可以了。
这次我们需要全排列套全排列,才能使得最后的对应顺序恰好为:
[gcd(v_1,v_2),gcd(v_1,v_3),gcd(v_1,v_4),gcd(v_2,v_3),gcd(v_2,v_4),gcd(v_3,v_4)
]
[lcm(v_1,v_2),lcm(v_1,v_3),lcm(v_1,v_4),lcm(v_2,v_3),lcm(v_2,v_4),lcm(v_3,v_4)
]
接下来,我们可以像前面一样先求出(v_1,v_2,v_3)的值,然后计算出(v_4)的值并检验即可。
具体实现详见代码。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define LL long long
using namespace std;
int n,m;__int128 a[10],b[10];
Tp I void read(Ty& x)//读入__int128
{
char c;x=0;W(!isdigit(c=getchar()));
W(x=(x<<3)+(x<<1)+(c&15),isdigit(c=getchar()));
}
Tp I Ty gcd(Con Ty& x,Con Ty& y) {return y?gcd(y,x%y):x;}//求gcd
class Dfser_for_Three
{
private:
bool vis[10];__int128 s[10];
I bool Calc()//求答案
{
__int128 v1,v2,v3;if(gcd(a[1]*s[1],a[2]*s[2])%a[3]) return 0;//判无解
v1=gcd(a[1]*s[1],a[2]*s[2])/a[3],v2=a[1]*s[1]/v1,v3=a[2]*s[2]/v1;//求出v1,v2,v3
if(v2*v3!=a[3]*s[3]||gcd(v1,v2)^a[1]||gcd(v1,v3)^a[2]||gcd(v2,v3)^a[3]) return 0;//判无解
return printf("%lld %lld %lld
",(LL)v1,(LL)v2,(LL)v3),1;//输出答案
}
public:
I bool dfs(CI x)//全排列
{
if(x>3) return Calc();
for(RI i=1;i<=3;++i) if(!vis[i]&&!(b[i]%a[x]))//剪枝
{
if(vis[i]=1,s[x]=b[i],dfs(x+1)) return vis[i]=0,1;
vis[i]=0;
}return 0;
}
}D3;
class Dfser_for_Four
{
private:
bool vis1[10],vis2[10];__int128 s1[10],s2[10];
I bool Calc()//求答案,与上面类似
{
__int128 v1,v2,v3,v4;if(gcd(s1[1]*s2[1],s1[2]*s2[2])%s1[4]) return 0;
v1=gcd(s1[1]*s2[1],s1[2]*s2[2])/s1[4],v2=s1[1]*s2[1]/v1,v3=s1[2]*s2[2]/v1;//求出v1,v2,v3
if(s1[3]*s2[3]%v1) return 0;v4=s1[3]*s2[3]/v1;//求出v4
if(v2*v3!=s1[4]*s2[4]||v2*v4!=s1[5]*s2[5]||v3*v4!=s1[6]*s2[6]) return 0;//判无解
if(gcd(v1,v2)^s1[1]||gcd(v1,v3)^s1[2]||gcd(v1,v4)^s1[3]) return 0;//判无解
if(gcd(v2,v3)^s1[4]||gcd(v2,v4)^s1[5]||gcd(v3,v4)^s1[6]) return 0;//判无解
return printf("%lld %lld %lld %lld
",(LL)v1,(LL)v2,(LL)v3,(LL)v4),1;//输出答案
}
I bool dfs2(CI x)//第二层全排列
{
if(x>6) return Calc();
for(RI i=1;i<=6;++i) if(!vis2[i]&&!(b[i]%s1[x]))
{
if(vis2[i]=1,s2[x]=b[i],dfs2(x+1)) return vis2[i]=0,1;
vis2[i]=0;
}return 0;
}
public:
I bool dfs1(CI x)//第一层全排列
{
if(x>6) return dfs2(1);
for(RI i=1;i<=6;++i) if(!vis1[i])
{
if(vis1[i]=1,s1[x]=a[i],dfs1(x+1)) return vis1[i]=0,1;
vis1[i]=0;
}return 0;
}
}D4;
int main()
{
RI Ttot,i;cin>>Ttot>>n,m=n*(n-1)>>1;W(Ttot--)
{
for(i=1;i<=m;++i) read(a[i]);for(i=1;i<=m;++i) read(b[i]);
if(n==2) {printf("%lld %lld
",(LL)a[1],(LL)b[1]);continue;}//对于两个数直接输出
if(n==3) {D3.dfs(1);continue;}D4.dfs1(1);
}return 0;
}