把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5316】恋恋的数学题(数学)

点此看题面

大致题意: 乱序给出\(k\)个数两两\(gcd\)\(lcm\),让你求出这\(k\)个数。

前言

比赛时看到这题心想神仙题,然后发现\(2\le k\le4\)。。。

于是又想快一个小时,才差不多想到了正解。

结果写完之后少加了一句检验,就被卡掉\(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) \]

然后如果你知道一个很显然的性质,那么这题就很水了:

\[x\cdot y=gcd(x,y)\cdot lcm(x,y) \]

也就是说,我们可以将上面的式子两两相乘得到\(v_1\cdot v_2,v_1\cdot v_3,v_2\cdot v_3\)的值。(注意相乘会爆\(long\ long\),因此需要开\(\_\_int128\)

然后,如果我们求出\(v_1\cdot v_2,v_1\cdot v_3\)\(gcd\),则它就相当于是\(v_1\cdot gcd(v_2,v_3)\)

因此,我们用\(gcd(v_1\cdot v_2,v_1\cdot v_3)\)去除以\(gcd(v_2,v_3)\),就得到了\(v_1\)的值!

\(v_2\)\(v_3\)既然已知与\(v_1\)的乘积,就可以直接通过除法算出。

注意在枚举到的一种排列中,有许多无解的情况需要特判,列举如下:

  • 两个数对应的\(lcm\)不能整除这两个数对应的\(gcd\)
  • \(gcd(v_1\cdot v_2,v_1\cdot v_3)\)不能整除\(gcd(v_2,v_3)\)
  • 最后算出的\(v_2\cdot 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\n",(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\n",(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\n",(LL)a[1],(LL)b[1]);continue;}//对于两个数直接输出
		if(n==3) {D3.dfs(1);continue;}D4.dfs1(1);
	}return 0;
}
posted @ 2019-04-21 15:51  TheLostWeak  阅读(327)  评论(0编辑  收藏  举报