1127: [POI2008]KUP
https://lydsy.com/JudgeOnline/problem.php?id=1127
分析:
如果存在一个点大于等于k,小于等于2k的话,直接输出。
否则把点分成两类,一类是<k的,另一类是大于2k的,大于2k的一定没用。
然后找一个全部由小于2k的点中组成一个的矩形(悬线法),这个矩形有三种情况:1、<k,没用;2、大于等于k,小于等于2k,输出;3、大于2k,它的子矩阵中一定存在一个合法的矩阵(因为每个元素都是<k的,所以增加一个元素不可能直接使面积从小于k变成大于等于2k)。
考虑如何对一个大于等于2k的矩形找到它的合法的子矩阵。每次删掉一行或者一列一定可以找到。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 #include<cctype> 7 #include<set> 8 #include<queue> 9 #include<vector> 10 #include<map> 11 #include<cstdlib> 12 using namespace std; 13 typedef long long LL; 14 15 inline int read() { 16 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 17 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 18 } 19 20 const int N = 2005; 21 22 LL sum[N][N], k; 23 int a[N][N], U[N][N], L[N], R[N], n; 24 25 void pd(int u,int d,int l,int r) { 26 if (u > d || l > r) return ; 27 LL now = sum[d][r] - sum[d][l - 1] - sum[u - 1][r] + sum[u - 1][l - 1]; 28 if (now < k) return ; 29 if (now >= k && now <= k + k) { 30 printf("%d %d %d %d",l, u, r, d); exit(0); 31 } 32 if (d - u > r - l) { 33 pd(u + 1, d, l, r); pd(u, d - 1, l, r); 34 pd(u, d, l + 1, r); pd(u, d, l, r - 1); 35 } 36 else { 37 pd(u, d, l + 1, r); pd(u, d, l, r - 1); 38 pd(u + 1, d, l, r); pd(u, d - 1, l, r); 39 } 40 } 41 42 int main() { 43 k = read(), n = read(); 44 for (int i = 1; i <= n; ++i) 45 for (int j = 1; j <= n; ++j) { 46 a[i][j] = read(); 47 sum[i][j] = a[i][j] + sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1]; 48 if (a[i][j] >= k && a[i][j] <= k + k) { printf("%d %d %d %d ",j, i, j, i); return 0; } 49 } 50 for (int i = 1; i <= n; ++i) 51 for (int j = 1; j <= n; ++j) 52 U[i][j] = a[i][j] <= k + k ? U[i - 1][j] + 1 : 0; 53 for (int i = 1; i <= n; ++i) L[i] = 0, R[i] = n + 1; 54 for (int i = 1; i <= n; ++i) { 55 int last = 0; 56 for (int j = 1; j <= n; ++j) { 57 if (a[i][j] <= k + k) L[j] = max(L[j], last + 1); 58 else last = j, L[j] = 0; 59 } 60 last = n + 1; 61 for (int j = n; j >= 1; --j) { 62 if (a[i][j] <= k + k) R[j] = min(R[j], last - 1); 63 else last = j, R[j] = n + 1; 64 } 65 for (int j = 1; j <= n; ++j) 66 if (U[i][j] && L[j] >= 1 && R[j] <= n) pd(i - U[i][j] + 1, i, L[j], R[j]); 67 } 68 puts("NIE"); 69 return 0; 70 }