0820 T3 好的网格

来源:互联网 发布:网络情歌《恋恋红尘》 编辑:程序博客网 时间:2024/05/16 06:10

原题链接

60 pts

爆搜吧!少年!

90 pts

发现如果有一个点满足该点为所在列最大元素并且为所在行最小元素则说明该矩阵合法。
所以我们可以只枚举这个点所在位置,之后将这个点所在行的所有元素排序,所在列的所有元素排序。
最后枚举这个点的权值,在这两个数列中二分,分别求出两个数列中比这个点大和小的数的个数。
时间复杂度O(n^3 log n)

100 pts

我们可以考虑枚举最终满足条件的的这个点的权值是多少。
在枚举的同时,我们实时维护每一行比这个数小的数的个数,以及每一列比这个数大的数的个数。
将个数最小的行和个数最小的列进行组合即可。
时间复杂度O(n^2 log n)

代码

#include<cstdio>#include<utility>#include<algorithm>using namespace std;const int N = 1100000;const int M = 1100;int n, m, x, A[M], B[M], C[N], ans, j, SS[N], TT[N];pair<int, int> a[N]; int main() {    scanf("%d", &n);    m = n*n;    ans = n*2-1;    for(int i = 0; i < m; ++i) {        scanf("%d", &a[i].first);        a[i].second = i;    }    sort(a, a+m);//重排序     for(int i = 0, j; i < m; i=j) {        TT[i] = TT[i-1];        for(j = i; a[j].first == a[i].first && j<m; ++j) {            x = a[j].second;            B[x%n]++;            TT[i] = max(TT[i], B[x%n]);        }        for(int k = i; k < j; ++k)            TT[k] = TT[i];    }    for(int i = m-1, j; i >= 0; i=j) {        SS[i] = SS[i+1];        for(j = i; a[j].first == a[i].first && j>=0; --j) {            x = a[j].second;            A[x/n]++;            SS[i] = max(SS[i], A[x/n]);        }        for(int k = i; k > j; --k)            SS[k] = SS[i];    }    for(int i = 0; i < m; ++i) {        ans = min(n-SS[i]+n-TT[i], ans);    }    printf("%d\n", ans);    return 0;}
原创粉丝点击