这道题有多解,下面给出一种无需二分的做法。
Hint 1
先假设已经求出了 $size$。观察题目所给条件,是否可以把网格分成两部分,使得每部分里互不影响,只需要考虑两部分之间的冲突?
Hint 2
按行的奇偶性来分,那么网格应当是这样的:11111
2 2 2
11111
2 2 2
11111
怎样安排数字,才能最大化利用上面Hint 1的性质?
Hint 3
存在一种安排方法,使得只有一种数字 $x$ 可能出现冲突。在放置 $x$ 时,会出现什么问题?如何避免?题解
假设 $size$ 为最小边长。考虑到 (mat_{i,j} eq mat_{i+1,j+1}) 且 (mat_{i,j+1} eq mat_{i+1,j})。
我们将网格按行的奇偶性分成两部分 (S_1), (S_2)。
11111
2 2 2
11111
2 2 2
11111
发现,每部分里的数字两两不影响,只有两部分间才可能出现冲突。
然后,我们如果把所有相同的数字放在一起,按某种顺序排好,先填 (S_1), 再填 (S_2),可以做到,只有1种数字 (x) 同时在 (S_1) 与 (S_2) 中出现。理解一下,因为数字是一段一段的,肯定只有一段从中间被分开了。
顺便算出 (x) 留在 (S_1) 中的个数 (num) (则在 (S_2) 中的有 (cnt_{x} - num) 个)。
为了不冲突,把(S_1) 里的放在下图 (A) 处,把(S_2)里的放在 (B) 处。
A A A
B B B
A A A
B B B
A A A
这会带来新的问题:(S_1) 里最多只能放 (lim = (leftlceildfrac{size}{2} ight ceil)^2) 个,可能不够放。为了避免,我用的方法是:把 (a_i) 排序,按 (a_i) 的降序填数。
简单证明一下,设 (n geq 2) ,(cap = size imes leftlceildfrac{size}{2} ight ceil) 为 (S_1) 的大小,则(a_1 geq a_2 geq ... geq a_n)。显然,(a_1) 对应的数字不会成为 (x)。
假设 (x) 是 (a_k) 所对应的,则 (sum1 = a_1 + a_2 + ... + a_{k-1} leq cap),(sum2 = a_1 + a_2 + ... + a_k > cap)。因此 (a_k leq dfrac{cap}{k})。而 (num < a_k)。
(k = 2) 时,(num) 最大值可达 (dfrac{cap}{2}),显然 (lim geq dfrac{cap}{2}) 。可见 (lim) 恒不小于 (num)。
剩下的数字呢?(x) 前面的都放 (S_1),后面的都放 (S_2)。
求 (size) 的方法还没说呢。上述构造方法可以保证,满足下面两个条件的输入都能找到解。
1.(m leq size^2 - (leftlfloordfrac{size}{2} ight floor)^2)
2.(max{a_i} leq cap)
枚举即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mit map<int,int>::iterator
#define sit set<int>::iterator
#define itrm(g,x) for(mit g=x.begin();g!=x.end();g++)
#define itrs(g,x) for(sit g=x.begin();g!=x.end();g++)
#define ltype int
#define rep(i,j,k) for(ltype(i)=(j);(i)<=(k);(i)++)
#define rap(i,j,k) for(ltype(i)=(j);(i)<(k);(i)++)
#define per(i,j,k) for(ltype(i)=(j);(i)>=(k);(i)--)
#define pii pair<int,int>
#define fi first
#define se second
#define mpr make_pair
#define pb push_back
#define fastio ios::sync_with_stdio(false)
#define check(x) if(x>=mod) x-=mod
const int inf=0x3f3f3f3f,mod=1000000007;
const double pi=3.1415926535897932,eps=1e-6;
void chmax(int &x,int y){if(x < y) x = y;}
void chmin(int &x,int y){if(x > y) x = y;}
int qpow(int x,int y){
int ret = 1;
while(y) {
if(y & 1) ret = (ll)ret * x % mod;
x = (ll)x * x % mod;
y >>= 1;
}
return ret;
}
int n,m,mx,ans[1005][1005];pii a[100005];
void solve()
{
scanf("%d%d",&m,&n);
rep(i,1,n) scanf("%d",&a[i].fi),a[i].se = i;
sort(a+1,a+n+1);reverse(a+1,a+n+1);
mx = 1;rep(i,2,n) if(a[mx] < a[i]) mx = i;
int s = 0;while(s * ((s + 1) / 2) < a[mx].fi || (s * s) - ((s / 2) * (s / 2)) < m) s++;
int cap = s * ((s + 1) / 2);
int id = n + 1, rest = 0;rep(i,1,n) if(rest + a[i].fi > cap) {id = i;break;} else rest += a[i].fi;
int u = 1, v = 1;
int num = cap - rest;
if(id <= n)rep(i,1,num) {
ans[u][v] = a[id].se;
v += 2;
if(v > s) v = 1, u += 2;
}
u = 1;v = 1;
rap(i,1,id) {
while(a[i].fi){
if(!ans[u][v]) ans[u][v] = a[i].se, a[i].fi--;
v++;
if(v > s) v = 1, u += 2;
}
}
u = 2;v = 1;
if(id <= n) rep(i,1,a[id].fi - num) {
ans[u][v] = a[id].se;
v += 2;
if(v > s) v = 1, u += 2;
}
rep(i,id+1,n) {
while(a[i].fi){
if(!ans[u][v]) ans[u][v] = a[i].se, a[i].fi--;
v += 2;
if(v > s) v = 1, u += 2;
}
}
printf("%d
",s);
rep(i,1,s) rep(j,1,s) printf("%d%c",ans[i][j],j==s?'
':' '),ans[i][j] = 0;
}
int main()
{
int T;scanf("%d",&T);while(T--) solve();return 0;
}