其他分享
首页 > 其他分享> > cf1521 E. Nastia and a Beautiful Matrix

cf1521 E. Nastia and a Beautiful Matrix

作者:互联网

题意:

你有 \(a_i\) 个数字 \(i\),要把它们都放进 \(n*n\) 网格内,每格可以为空或者放一个数。要求对于任何 \(2*2\) 子网格,有数的位置不能超过 \(3\) 个,且对角线上的数不能相等

输出放数后的网格图,要求 \(n\) 最小

思路:

image

当 \(n\) 确定的时候要咋放?

首先横纵坐标均为偶数的位置(图中白色)不放数,这样就能满足第一个要求,且被浪费的格子数最少。为了放下所有数,就要求 \(sum \le n^2-\lfloor \frac n2 \rfloor ^2\)

那么在 \(2*2\) 网格内与白色格子对角的所有位置(图中蓝色)就能随便放

记出现次数最多的数为 \(x\),其出现次数为 \(a_x\),那么当 \(a_x\) 不超过蓝+黄格数,即 \(a_x\le n\cdot\lceil \frac n2 \rceil\) 时一定有合法方案

方案:先放出现次数最多的数 \(x\) ,再随便放其他数,放完一个再到另一个。先在黄色格放数、黄满了放蓝、蓝满了再放红。

啥时候会违背第二个要求?首先 \(x\) 顶多把黄蓝都放满,故肯定不会违背;如果某个数 \(y\neq x\) 放了一些黄格,然后放满蓝格,再放一些红格,这些黄格红格中恰有某对在对角位置的话就寄了,但注意到黄格数小于等于蓝格数,而这样一来 \(x\) 全在黄格里于是 \(x\) 的数量比黄格数少,\(y\) 比蓝格数多故比 \(x\) 还多,矛盾

//代码0难度,建议别看
const signed N = 5 + 1e5;
int sum, k, n, a[N];

void nxt(int& i, int& j) { //下一个位置
    if(j + 2 <= n) j += 2;
    else if(i + 2 <= n) i += 2, j = j % 2 ? 1 : 2;
    else if(i % 2 && !(j % 2)) i = j = 1; //黄变蓝
    else if(i % 2 && j % 2) i = 2, j = 1; //蓝变红
}

void sol() {
    cin >> sum >> k;
    for(int i = 1; i <= k; i++) cin >> a[i];

    int big = max_element(a + 1, a + 1 + k) - a;
    
    ll l = 0, r = 2e5; //二分找n
    while(l < r) {
        ll mid = l + r >> 1;
        if(sum<=mid*mid-(mid/2)*(mid/2) && a[big]<=(mid+1)/2*mid)
            r = mid;
        else l = mid + 1;
    }

    n = l; vector<vector<int>> g(n+1,vector<int>(n+1,0));
    int x = 1, y = 2; //起点
    if(n == 1) x = y = 1; //这种写法要特判
    while(a[big])
        g[x][y] = big, a[big]--, nxt(x, y);
    for(int i = 1; i <= k; i++)
        while(a[i]) g[x][y] = i, a[i]--, nxt(x, y);
    
    cout << n << endl; for(int i = 1; i <= n; i++) //输出答案
        for(int j = 1; j <= n; j++) cout << g[i][j] << "\n "[j<n];
}

标签:Beautiful,cf1521,int,big,Nastia,位置,网格,黄格,sum
来源: https://www.cnblogs.com/wushansinger/p/16496273.html