【思维 && 构造到 0 位置的元素值满足曼哈顿距离的矩阵】Codeforces Round #495 (Div. 2) D. Sonya and Matrix

Step1 Problem:

给你 t 个数(a1, a2….at)至少有一个 0,要你构造 n*m 的矩阵,该矩阵的元素的值满足到 0 这个元素的位置的曼哈顿距离。曼哈顿距离:两个点的坐标差的绝对值和。
如果构造出满足条件的矩阵,输出 0 的坐标。
数据范围:
1<=t<=1e6, 0<=a[i]<=t, n*m = t.

Step2 Ideas:

我们假定 0 的位置 (x, y) 尽可能的靠近 (1, 1)。
那么距离 0 最远的距离为 (n, m),出现元素的最大值 Max = n+m-x-y.
我们 i 从 1 开始枚举,如果 i 出现的次数不是 4*i,这时候对于 (i-1) 这个元素一定得在边界。如果我们让其有限靠上边界,这时候 x 值就等于 i.
已知 Max, n, m, x,求出 y 然后判断是否满足要求即可。

Step3 Code:

#include
using namespace std;
const int N = 1e6+5;
struct node
{
    int u, v, step;
};
int vis[N], tvis[N];
bool solve(int x, int y, int n, int m)
{
    memset(tvis, 0, sizeof(tvis));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            int tmp = abs(x-i)+abs(y-j);
            tvis[tmp]++;
            if(tvis[tmp] > vis[tmp]) return 0;
        }
    }
    return 1;
}
int main()
{
    int n, num;
    scanf("%d", &n);
    memset(vis, 0, sizeof(vis));
    int Max = 0;
    for(int i = 0; i scanf("%d", &num);
        Max = max(Max, num);
        vis[num]++;
    }
    int flag = 0, x = 0, y;
    for(int i = 1; i <= n; i++)
    {
        if(vis[i] > i*4) {//大于一定构不成满足条件矩阵
            flag = 1; break;
        }
        if(vis[i] == i*4) continue;
        x = i; break;
    }
    if(flag || !x) {//如果找不到,全是 4 的倍数,一样构不成矩阵
        printf("-1\n");
        return 0;
    }
    for(int i = 1; i <= n; i++)
    {
        if(n%i == 0) {
            y = i+n/i-x-Max;
            if(solve(x, y, i, n/i)) {//知道 Max, n, m, x, y 判断所给数据是否满足。
                printf("%d %d\n", i, n/i);
                printf("%d %d\n", x, y);
                return 0;
            }
        }
    }
    printf("-1\n");
    return 0;
}

你可能感兴趣的:(比赛卡住题)