题目链接:B.Mask Allocation
题意
本题的题意是个难点,我们花了将近一个多小时才把题意搞懂。。
给你n和m,让你构造一个数组,要求数组里的数不能拆分只能合并,使之可以合并为n个m和m个n,答案可能有多种,要求输出长度最小的。
题解
本题我们猜了一个结论,发现选中的数字可以通过欧几里得算法(求gcd)确定,而每一步求解的结果为选中的数字。
以10 6为例:
选中的数字有6,10%6,6%(10%6)。
所以很容易确定构造数组中的数字,现在我们需要确定数字的个数。通过猜想加验证,发现次数为
m
∗
⌊
n
/
m
⌋
{m*\lfloor n/m \rfloor}
m∗⌊n/m⌋。按照这个写法模拟即可。
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
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<int,int>
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");
}
}