[2020牛客暑期多校训练营第七场] B.Mask Allocation GCD

题目链接:B.Mask Allocation

题意

本题的题意是个难点,我们花了将近一个多小时才把题意搞懂。。
给你n和m,让你构造一个数组,要求数组里的数不能拆分只能合并,使之可以合并为n个mm个n,答案可能有多种,要求输出长度最小的。

题解

本题我们猜了一个结论,发现选中的数字可以通过欧几里得算法(求gcd)确定,而每一步求解的结果为选中的数字。
以10 6为例:
选中的数字有6,10%6,6%(10%6)。
所以很容易确定构造数组中的数字,现在我们需要确定数字的个数。通过猜想加验证,发现次数为 m ∗ ⌊ n / m ⌋ {m*\lfloor n/m \rfloor} mn/m。按照这个写法模拟即可。

代码

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//extern "C"{void *__dso_handle=0;}
typedef long long ll;
typedef long double ld;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define pii pair

const double PI=acos(-1.0);
const double eps=1e-6;
const ll mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
const int maxm=100+10;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

int fac[maxn],cnt[maxn];

int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		if(m>n) swap(n,m);
		if(n%m==0)
		{
			printf("%d\n",n);
			for(int i=0;i<n;i++) printf("%d ",m);
			printf("\n");
			continue ;
		}
		int len=0;
		cnt[len]=m;
		while(m!=0)
		{
			int t=n%m;
			cnt[len]*=(n/m);
			n=m;
			m=t;
			fac[len++]=n;
			cnt[len]=t;
		}
		ll sum=0;
		for(int i=0;i<=len;i++) sum+=cnt[i];
		printf("%lld\n",sum);
		for(int i=0;i<=len;i++)
		{
			for(int j=0;j<cnt[i];j++) printf("%d ",fac[i]);
		}
		printf("\n");
	}
}

你可能感兴趣的:(数论,数学)