F - Let's Play the Hat?

题意: n个人m张桌子玩k次游戏。每个人必须玩k次游戏。每个桌子的人数都是 n/m (上取整 或 下取整)。

定义 bib_i 为第ii 个人在人数为 n/m(上取整) 的桌子上玩的游戏次数。对任意 $ i, j $ 满足 bibj<=1|b_i - b_j| <= 1

Solution: 首先,m张桌子分给n个人,显然每张桌子的人数是确定的——

大桌为n%m个,小桌为 m - n%m个。(每张桌子先坐 n/m(下取整)个人,剩下的 n%m 个人随便挑一个坐)

我们要使每个人在大桌上坐的次数相差不超过1。策略是这样的:

每次让坐在大桌上次数较少的人坐大桌,坐不满从较多的人补。这样显然可以保证相差不超过1。

实现的话可以考虑利用vector的rotate来滚动选择的人,每次坐大桌的人都让其移动到整个序列的最后排队。

#include <bits/stdc++.h>
using namespace std;
inline void read(int &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
const int N = 2e5 + 5;
int t, n, m, k;
int main()
{
    read(t);
    while(t--)
    {
        read(n); read(m); read(k);
        vector<int>v(n);
        for(int i = 0; i < n; i++) v[i] = i + 1;
        int bt = n % m, bn = ceil(1.0 * n / m), sn = n / m;
        for(int i = 1; i <= k; i++)
        {
            int pos = 0;
            for(int j = 1, num; j <= m; j++)
            {
                if(j <= bt) num = bn; else num = sn;
                cout << num << ' ';
                while(num--) cout << v[pos++] << ' ';
                puts("");
            }
            rotate(v.begin(), v.begin() + bn * bt, v.end());
        }
        puts("");
    }
    return 0;
}