[CF1521E] Nastia and a Beautiful Matrix

前言

莫名其妙洛谷rk1,CF rk2。(指运行时间)

于是水博客

题目

CF

洛谷

讲解

有一个贪心策略很好想,如果确定了矩阵边长 \(n\),我们一定会让坐标为 \((2k_1,2k_2),k_1,k_2\in N^+\) 的格子空出来。

然后我们考虑将剩下的格子进行分类,建议画图理解(由于太懒就不上传图了)。其实就是图太丑。

对于坐标为 \((1+2k_1,1+2k_2),k_1,k_2\in N\) 的格子,我们显然可以随便填,定义其为颜色3。

而剩下的格子可以二染色,定义其为颜色1,2。

我们可以将数字数量按从小到大排序,方格按颜色1,3,2或2,3,1排序,然后填就可以了。

至于 \(n\),需要满足两个条件:

  • \(n\cdot n\) 的矩阵可以包含 \(m\) 个数。
  • 没有数字的数量超过颜色1与颜色2格子数的和。

时间复杂度 \(O(\sum k\log_2k)\)

当然,如果你优化排序方式,也可以做到 \(O(\sum m)\) 级别。

代码

struct node
{
	int a,ID;
	bool operator < (const node &px)const{
		return a > px.a;
	}
}s[MAXN];

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	for(int T = Read(); T ;-- T)
	{
		MAX = n = 0; m = Read(); k = Read();
		while(n * n - (n>>1) * (n>>1) < m) n++;
		for(int i = 1;i <= k;++ i) s[i].a = Read(),MAX = Max(MAX,s[i].a),s[i].ID = i;
		sort(s+1,s+k+1);
		while(((n+1)>>1) * ((n+1)>>1) + (n>>1) * ((n+1)>>1) < MAX) n++;
		for(int i = 1;i <= n;++ i)
			for(int j = 1;j <= n;++ j)
				ans[i][j] = 0;
		int now = 1;
		for(int i = 2;i <= n && now <= k;i += 2)//二染色之一种格子
			for(int j = 1;j <= n && now <= k;j += 2)
			{
				ans[i][j] = s[now].ID; s[now].a--;
				while(!s[now].a && now <= k) now++;
			}
		for(int i = 1;i <= n && now <= k;i += 2)//随便填
			for(int j = 1;j <= n && now <= k;j += 2)
			{
				ans[i][j] = s[now].ID; s[now].a--;
				while(!s[now].a && now <= k) now++;
			}
		for(int i = 1;i <= n && now <= k;i += 2)//二染色另外一种格子
			for(int j = 2;j <= n && now <= k;j += 2)
			{
				ans[i][j] = s[now].ID; s[now].a--;
				while(!s[now].a && now <= k) now++;
			}
		Put(n,'\n');
		for(int i = 1;i <= n;++ i,putchar('\n'))
			for(int j = 1;j <= n;++ j)
				Put(ans[i][j],' ');
	}
	return 0;
}
posted @ 2021-05-11 22:32  皮皮刘  阅读(41)  评论(0编辑  收藏  举报