Codeforces 659F F - Polycarp and Hay

题意 : 

题意:给你n, m (1 ≤ n,m ≤ 1000) and k (1 ≤ k ≤ 10^18),n,m表示一个 n*m的矩阵,矩阵中的每个元素小于等于10^9,问能不能构成另外一个矩阵。

这个矩阵里面相同位置的数只能小于等于原来矩阵里面相同位置的数。并且在这个矩阵中存在一个连通块这个连通块中的数都等于这个连通块中最小的数,并且

连通块的权值和恰好等于k

让你输出一个可行解。


solution : 对于这个题目用并查集维护连通块的最大数目,讲矩阵中的数从大到小排序,(因为这样排序可以使得每次得到一个新的数都满足它小于等于前面所有的数,这样就可以直接加入到并查集中 ) 每次选择一个数,看看这个数是不是k的因子 ,如果是就判断这个数乘以它所在集合里数的个数是不是大于等于k的,如果是我们就找到了一个可行的位置,用bfs输出答案即可。

 坑点:这个题最后可能只剩下一个数。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
struct node {
    int x,y;
    ll num;
}a[maxn];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int cnt = 0;
int n,m;
ll k;
bool vis[1005][1005] = {0};
ll g[1005][1005] = {0};
int p[maxn] = {0};
ll sum[maxn] = {0};
bool cmp (node a,node b) {
    return a.num > b.num;
}
int find (int x) {
    if (x == p[x])return x;
    return p[x] = find (p[x]);
}
void u (int x,int y) {
    x = find (x);
    y = find (y);
    if (x != y) {
        p[x] = y;
        sum[y] += sum[x];
        sum[x] = 0;
    }
}
void bfs (int pos) {
    ll temp = (k + 0.5) / a[pos].num;
    int x = a[pos].x;
    int y = a[pos].y;
    memset (vis,0,sizeof (vis));
    vis[x][y] = 1;
    queue <node> q;
    q.push (a[pos]);
    while (!q.empty()) {
        node u = q.front();
        q.pop ();
        for (int i = 0;i < 4; ++ i) {
            int xx = u.x + dx[i];
            int yy = u.y + dy[i];
            if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && g[xx][yy] >= g[x][y] && !vis[xx][yy]) {
                vis[xx][yy] = 1;
                temp --;
                if (temp == 1) return ;
                q.push ({xx,yy,0});
            }
        }
    }
    return ;
}
int main () {
    ios_base :: sync_with_stdio(false);
    int ok = 0;
    cin >> n >> m >> k;
    for (int i = 1;i <= n; ++ i) {
        for (int j = 1;j <= m; ++ j) {
            a[cnt].x = i;
            a[cnt].y = j;
            cin >> a[cnt].num;
            g[i][j] = a[cnt].num;
            cnt ++;
        }
    }
    sort (a,a + cnt,cmp);
    for (int i = 0;i < maxn; ++ i) {
        p[i] = i;
        sum[i] = 1;
    }
    for (int i = 0;i < cnt ; ++ i) {
        vis[a[i].x][a[i].y] = 1;
        if (a[i].num == k) {
            memset (vis,0,sizeof (vis));
            cout << "YES" << endl;
            vis[a[i].x][a[i].y] = 1;
            for (int u = 1;u <= n; ++ u) {
                for (int j = 1;j <= m; ++ j) {
                    if (vis[u][j]) {
                        cout << a[i].num << ' ';
                    }
                    else {
                        cout << 0 << ' ';
                    }
                }
                cout << endl;
            }
            return 0;
        }
        for (int j = 0;j < 4; ++ j) {
            int xx = a[i].x + dx[j];
            int yy = a[i].y + dy[j];
            if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && vis[xx][yy]) {
                u ((xx - 1) * m + yy,(a[i].x - 1) * m + a[i].y);
                if (k % a[i].num == 0) {
                    int fa = p[(a[i].x - 1) * m + a[i].y];
                    if (sum[fa] * a[i].num >= k) {
                        ok = 1;
                        cout << "YES" << endl;
                        bfs (i);
                        for (int u = 1;u <= n; ++ u) {
                            for (int j = 1;j <= m; ++ j) {
                                if (vis[u][j]) {
                                    cout << a[i].num << ' ';
                                }
                                else {
                                    cout << 0 << ' ';
                                }
                            }
                            cout << endl;
                        }
                        return 0;
                    }
                }
            }
        }
    }
    cout << "NO" << endl;
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值