牛客多校第七场 Mask Allocation(GCD)

在这里插入图片描述
题意:
有n*m个口罩,要求分成最小数目的盒子,使得能组成m组,每组n个口罩。且可以组成n组,每组m个口罩。且最后盒子大小组成的序列字典序最大。

思路:
不妨设 n > m n>m
则我们要满足分成 n n 组,每组m个,则每个盒子至多为 m m ,为了保证字典序最大且块最少,当前盒子的大小能为m就为m。

考虑医院数量为m,则分成m组每组n个。
每个医院可以分配一个装着m个的口罩的盒子,则每个医院还需要n-m个口罩,那么还需要能将剩下的口罩分成 m m 组,每组 n m n-m 个口罩。

再考虑医院数量为n,则分成n组每组m个,则按照之前分发可以有 m m 个医院满足条件,剩下 n m n-m 个医院没有分到口罩。则还需要分成 n m n-m 组,每组分 m m 个口罩。

所以接下来的问题就可以变成 分成n-m组每组m个,且分成m组每组n-m个的子问题了,和原问题等价,类似GCD的辗转相除,递归解决就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <iostream>
#include <map>
#include <string>

using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;
const int maxn = 5000 + 7;

vector<int>vec;

int dfs(int n,int m) {
    if(n < m) swap(n,m);
    if(m == 0) return 0;
    int res = m;
    for(int i = 1;i <= m;i++) vec.push_back(m);
    res += dfs(m,n - m);
    return res;
}

int main() {
    int T;scanf("%d",&T);
    while(T--) {
        int n,m;scanf("%d%d",&n,&m);
        if(n == m) {
            printf("%d\n",n);
            for(int i = 1;i <= n;i++) {
                printf("%d ",n);
            }
            printf("\n");
            continue;
        }
        vec.clear();
        int ans = dfs(n,m);
        printf("%d\n",ans);
        for(int i = 0;i < vec.size();i++) {
            printf("%d ",vec[i]);
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/107825997