zoukankan      html  css  js  c++  java
  • 【洛谷5316】恋恋的数学题(数学)

    点此看题面

    大致题意: 乱序给出(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;
    }
    
  • 相关阅读:
    合并区间
    编程团体赛
    寻找数组的中间位置
    翻转链表2
    链表翻转
    CF1237H. Balanced Reversals
    arc108E
    agc028D
    CF1446D. Frequency Problem
    CF1439D. INOI Final Contests
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5316.html
Copyright © 2011-2022 走看看