题解 子集

传送门

并不会做

首先令 \(m=\frac{n}{k}\)要特判 k=1 和 m=1,以及总和除不尽集合数的情况
于是m是偶数时 \(i\)\(n-i+1\) 组合选就行
m是奇数的情况可以先按上面的策略选到剩 \(3k\)
考虑剩下的 \(3k\) 个怎么凑成 \(k\) 个和一样的集合
于是先把1到k按顺序放到k个集合中
然后用剩下的拼出一个等差数列
举个例子

1 6
2 7
3 8
4 9
5 10

1->10
2->8
3->6
4->9
5->7

于是问题解决(我承认这篇水了)

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF: *p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k, m;

namespace task1{
	void solve() {
		puts("Yes");
		int pos=1;
		for (int i=1; i<=k; ++i) {
			for (int j=1; j<=n/k/2; ++j) printf("%d %d ", pos, n-pos+1), ++pos;
			printf("\n");
		}
	}
}

namespace task{
	struct tpl{int val, x, y; inline void build(int a, int b){x=a; y=b; val=x+y;}}t[N];
	inline bool operator < (tpl a, tpl b) {return a.val<b.val;}
	void solve() {
		puts("Yes");
		int pos1=3*k+1, pos2=n;
		for (int i=1; i<=k; ++i)
			if (i<=(k+1)/2) t[i].build(i, k-2*(i-1));
			else t[i].build(i, k-2*(i-(k+1)/2)+1);
		sort(t+1, t+k+1);
		for (int i=1; i<=k; ++i) {
			for (int j=1; j<=(n-3*k)/k/2; ++j) printf("%d %d ", pos1, pos2), ++pos1, --pos2;
			printf("%d %d %d ", i, t[k-i+1].x+k, t[k-i+1].y+2*k);
			printf("\n");
		}
	}
}

signed main()
{
	freopen("subset.in", "r", stdin);
	freopen("subset.out", "w", stdout);

	int T=read();
	while (T--) {
		n=read(); k=read(); m=n/k;
		if (k==1) {puts("Yes"); for (int i=1; i<=n; ++i) printf("%d%c", i, " \n"[i==n]);}
		else if (m==1 || (m*(n+1)%2)) puts("No");
		else if (!(m&1)) task1::solve();
		else task::solve();
	}

	return 0;
}
posted @ 2021-11-04 21:33  Administrator-09  阅读(0)  评论(0编辑  收藏  举报