(多校)子集 (subset)

第一次考场切构造题

首先我们摸一下样例

有一个显然的结论

如果我们依次从左到右把 \(n\) 个数分成 \(\frac{n}{k}\)

并且每一份大小都为 \(k\)

那么每一个子集在每一组数中都恰好选一个

\[1.2.3 : 4.5.6 : 7.8.9 : 10.11.12 \]

所以,我们不妨把序列表示成:

\[1.2.3 : 1.2.3 : 1.2.3 : 1.2.3 \]

转换成矩阵:

\[1-1-1-1 \]

\[2-2-2-2 \]

\[3-3-3-3 \]

那么题意就转换成让每一列上的数互换,求一种方案使得每一行的数字之和相等

样例这种情况很好想,我么只要把 \(\frac{n}{2k}\) 列的数字 \(reverse\) 一下就好了

这种情况其实是针对 \(n/k\) 为偶数的情况的

考虑 \(n/k\) 为奇数的情况

容易发现我们只需要大力手玩一下前三列的数字,使其每一行的数字和相等

对于剩下的 \(n/k-3\) 列的数字按 \(n/k\) 为偶数的情况做就好了

Code
#include <bits/stdc++.h>
#define re register
#define int long long
// #define lls long long
#define pir make_pair
#define fr first 
#define sc second
#define db long double
using namespace std;
const int mol=998244353;
const int maxn=1e6+10;
const int INF=1e9+10;
inline int qpow(int a,int b) { int ans=1; while(b) { if(b&1) (ans*=a)%=mol; (a*=a)%=mol; b>>=1; } return ans; }
inline int read() {
    int s=0,w=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { s=s*10+ch-'0'; ch=getchar(); }
    return s*w;
}

int t,n,k,tot,fac[maxn];
vector<int>vec[maxn];
inline void wor() {
    for(re int i=1;i<=tot;i++) vec[i].clear(); 
    tot=n/k;
    for(re int i=1;i<=tot;i++) for(re int j=1;j<=k;j++) vec[i].push_back(j);
    if(tot&1) {
        if(fac[k]*3%k!=0) { puts("No"); return ; }
        int lim=fac[k]*3/k,fg=lim-1-k;
        for(re int i=1;i<=k;i++) { vec[2][i-1]=fg; vec[3][i-1]=lim-i-fg; fg++; if(fg>k) fg=1; }
        for(re int i=1;i<=(tot-3)/2;i++) reverse(vec[3+i].begin(),vec[3+i].end());
    } else {
        for(re int i=1;i<=tot/2;i++) reverse(vec[i].begin(),vec[i].end());
    }
    puts("Yes");
    for(re int i=1;i<=k;i++) {
        for(re int j=1;j<=tot;j++) printf("%lld ",(j-1)*k+vec[j][i-1]);
        puts("");
    }
}
signed main(void) {
    freopen("erp.in","r",stdin); freopen("erp.out","w",stdout);
    int lims=1e6;
    for(re int i=1;i<=lims;i++) fac[i]=fac[i-1]+i;
    t=read();
    while(t--) {
        n=read(); k=read();
        if(n==1) { puts("Yes 1"); continue; }
        if(n/k==1) { puts("No"); continue ; }
        wor();
    }
}
posted @ 2021-11-04 15:37  zJx-Lm  阅读(268)  评论(0编辑  收藏  举报