题目描述
输入描述:
输出描述:
示例1
输入
2
5 4
3 3
输出
8
4 4 4 4 1 1 1 1
3
3 3 3
题目大意
给定一个
n
n
n和
m
m
m,要求输出一种把
n
∗
m
n*m
n∗m分组的方案,使得这个分组的方案中能合并元素变成
n
n
n等分也能变成
m
m
m等分。输出分组的方案中字典序最大的那个,并在此之前输出分组的个数。
如:
5
,
4
5,4
5,4
4
,
4
,
4
,
4
,
1
,
1
,
1
,
1
4,4,4,4,1,1,1,1
4,4,4,4,1,1,1,1可以把后面
4
4
4个
1
1
1分别加到前面的
4
4
4上,变成
4
4
4等分
(
5
,
5
,
5
,
5
)
(5,5,5,5)
(5,5,5,5),也可以将后面的
1
1
1全部合并起来变成
4
4
4实现
5
5
5等分
(
4
,
4
,
4
,
4
,
4
)
(4,4,4,4,4)
(4,4,4,4,4)。
分析
灵光一闪
这题比赛的时候就做出来了,当时灵光一现就感觉是这么做的,找了几组数据就AC了。
先说说比赛的时候我的做法。
先列出两个数列,分别是全为
n
n
n的长为
m
m
m的和全为
m
m
m的长为
n
n
n的。然后将它们上下对齐。
下面以
5
,
3
5,3
5,3为例:
5
,
5
,
5
5,5,5
5,5,5
3
,
3
,
3
,
3
,
3
3,3,3,3,3
3,3,3,3,3
然后将相等的长度部分都减去较小的部分。
2
,
2
,
2
2,2,2
2,2,2
0
,
0
,
0
,
3
,
3
0,0,0,3,3
0,0,0,3,3
然后将
0
0
0的部分去掉。
2
,
2
,
2
2,2,2
2,2,2
3
,
3
3,3
3,3
然后将上面减掉的长度存入答案。即
a
n
s
=
{
3
,
3
,
3
}
ans=\{3,3,3\}
ans={3,3,3}。然后再进行上面的操作。即:
0
,
0
,
2
0,0,2\qquad
0,0,2
1
,
1
1,1\qquad
1,1
a
n
s
=
{
3
,
3
,
3
,
2
,
2
}
ans=\{3,3,3,2,2\}
ans={3,3,3,2,2}//减去相同
2
2\qquad
2
1
,
1
1,1\qquad
1,1
a
n
s
=
{
3
,
3
,
3
,
2
,
2
}
ans=\{3,3,3,2,2\}
ans={3,3,3,2,2}//去掉0,下同,直到都是0
1
1\qquad
1
0
,
1
0,1\qquad
0,1
a
n
s
=
{
3
,
3
,
3
,
2
,
2
,
1
}
ans=\{3,3,3,2,2,1\}
ans={3,3,3,2,2,1}
1
1\qquad
1
1
1\qquad
1
a
n
s
=
{
3
,
3
,
3
,
2
,
2
,
1
}
ans=\{3,3,3,2,2,1\}
ans={3,3,3,2,2,1}
0
0\qquad
0
0
0\qquad
0
a
n
s
=
{
3
,
3
,
3
,
2
,
2
,
1
,
1
}
ans=\{3,3,3,2,2,1,1\}
ans={3,3,3,2,2,1,1}
退出。发现
a
n
s
ans
ans就是答案,而且是字典序最大的。
当时是这么做了,也是冥冥之中有点感觉。也没仔细想过。
那么AC代码就放在这里,大家自己理解。
正解
接下来是正解。
首先我们考虑前几个的答案。假如我们默认
n
≥
m
n\ge m
n≥m,那么前
n
−
n
m
o
d
m
n-n\,mod\,m
n−nmodm个答案肯定是
m
m
m。因为如果大于
m
m
m,那么无法变成
n
n
n等分,小于的话字典序没有
m
m
m大。所以我们可以把前
m
m
m个填掉。
那么接下来,我要把剩下的几个填掉,那么,考虑需要满足什么。如果我这个填完之后,满足可以构成
n
m
o
d
m
n\,mod\,m
nmodm个
m
m
m以及能构成
m
m
m个
n
n
n就可以了。结果发现求解过程是类似于辗转相除法的,所以只要跑一趟
g
c
d
gcd
gcd就可以AC了。
与上面的对照,发现其实根本是一样的,上面的比较容易想到,而正解是每一步都是实的,比较稳。上面数组相减其实和这个辗转没有太大的区别,看官们可以结合起来啃啃。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 1<<30
using namespace std;
vector<int> ans;
void gcd(int n,int m)
{
if(m==0) return;
for(int i=0;i<(n/m)*m;i++) ans.push_back(m);
//存储答案
gcd(m,n%m);
}//gcd
int main()
{
int t,n,m,i;
scanf("%d",&t);
while(t--)
{
ans.clear();
scanf("%d%d",&n,&m);
if(n<m) swap(n,m);//nm的顺序没有关系,为了代码的方便,交换成n>=m
gcd(n,m);
printf("%d\n",ans.size());
for(i=0;i<ans.size();i++)
printf("%d ",ans[i]);
puts("");
}
return 0;
}
END
简单的规律题,其实很容易想到的。