题目链接:http://codeforces.com/contest/1200/problem/D
这题比赛时没想出来,赛后补题时想出来了,还是自己太菜了。。。
思路:这题按照暴力去做的话,时间肯定tle,所以我们得去优化。这题需要利用滑动窗口,利用滑动窗口,我们可以把时间降到O(N2),首先预处理每行每列的B的最大位置最小位置,然后接下来就可以去模拟了,我们想,题目给了一个边长为k的正方形可以覆盖,那么这一列(或一行)B的最大,最小位置是不是在边长为k的正方形内。这样就可以利用滑动窗口去搞了,我们用队列( 先进先出 )去模拟边长为k的窗口,就可以得到答案。注意我们先算出,原来就存在的白线有多少,模拟得时候不计这个答案。
1 #include <iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<cmath> 6 #include<map> 7 #include<set> 8 #include<queue> 9 #include<stack> 10 #include<vector> 11 #include<list> 12 #include<algorithm> 13 #include<time.h> 14 #include<sstream> 15 using namespace std; 16 long long GCD(long long a, long long b) { return b == 0 ? a : GCD(b, a%b); } 17 const long long inf = 0x7f7f7f7f; 18 const long long mod = 1e9 + 7; 19 double pi = acos(-1.0); 20 char str[2100][2100]; 21 int a[2100][2100]; 22 vector<int>r[2100], c[2100];//r统计每行产生得贡献是多少,c统计每列产生得贡献是多少 23 queue<int>val;//模拟滑动窗口 24 int n, k; 25 int R[2100], C[2100];//预处理白线所在的位置 26 void fact(int i, int minc[], int maxc[], int num) 27 { 28 int sum = 0; 29 for (int j = 1; j <= n; j++) 30 { 31 if (val.size() < k)//小于k时直接放入队列里 32 { 33 val.push(j); 34 if (minc[j] >= i && minc[j] < i + k && maxc[j] >= i && maxc[j] < i + k)//判断B是不是在正方形内 35 { 36 if (num == 0 && C[j] != 1) 37 sum++; 38 else if (num == 1 && R[j] != 1)//扣出白线所在的位置 39 sum++; 40 41 } 42 if (val.size() == k)//计算产生的贡献 43 { 44 if (num == 0) 45 c[i].push_back(sum); 46 else 47 r[j].push_back(sum); 48 } 49 } 50 else 51 { 52 int index = val.front(); 53 val.pop(); 54 val.push(j); 55 if (minc[index] >= i && minc[index] < i + k && maxc[index] >= i && maxc[index] < i + k)//需要减去之前第一个入队所产生的产生贡献 56 { 57 if (num == 0 && C[index] != 1) 58 sum--; 59 else if (num == 1 && R[index] != 1) 60 sum--; 61 } 62 if (minc[j] >= i && minc[j] < i + k && maxc[j] >= i && maxc[j] < i + k) 63 { 64 if (num == 0 && C[j] != 1) 65 sum++; 66 else if (num == 1 && R[j] != 1) 67 sum++; 68 } 69 if (num == 0) 70 c[i].push_back(sum); 71 else 72 r[j].push_back(sum); 73 } 74 } 75 while (!val.empty()) 76 val.pop(); 77 } 78 int main() 79 { 80 ios::sync_with_stdio(false); 81 cin.tie(0); cout.tie(0); 82 int minr[2100], minc[2100], maxr[2100], maxc[2100]; 83 cin >> n >> k; 84 for (int i = 1; i <= n; i++) 85 { 86 cin >> str[i]; 87 for (int j = 0; j < n; j++) 88 a[i][j + 1] = (str[i][j] == 'W' ? 0 : 1); 89 } 90 for (int i = 1; i <= n; i++)//预处理每行每列B的最大最小位置 91 { 92 int minn = n, maxn = 0; 93 for (int j = 1; j <= n; j++) 94 if (a[i][j]) 95 { 96 minn = min(minn, j); 97 maxn = max(maxn, j); 98 } 99 minr[i] = minn, maxr[i] = maxn; 100 minn = n, maxn = 0; 101 for (int j = 1; j <= n; j++) 102 if (a[j][i]) 103 { 104 minn = min(minn, j); 105 maxn = max(maxn, j); 106 } 107 minc[i] = minn, maxc[i] = maxn; 108 } 109 int ans = 0; 110 for (int i = 1; i <= n; i++)//算出原来就存在的白线数目 111 { 112 bool flag = false; 113 for (int j = 1; j <= n; j++) 114 if (a[i][j]) 115 flag = true; 116 if (!flag) 117 ans++, R[i] = 1; 118 flag = false; 119 for (int j = 1; j <= n; j++) 120 if (a[j][i]) 121 flag = true; 122 if (!flag) 123 ans++, C[i] = 1; 124 } 125 for (int i = 1; i <= n - k + 1; i++) 126 { 127 fact(i, minc, maxc, 0);//算出每行产生的贡献 128 fact(i, minr, maxr, 1);//算出每列产生的贡献 129 } 130 int maxn = 0;; 131 for (int i = 1; i <= n - k + 1; i++) 132 for (int j = 0; j < n - k + 1; j++) 133 maxn = max(maxn, r[i + k - 1][j] + c[i][j]);//每行每列的贡献加上得到的是正方形所产生的贡献 134 cout << ans + maxn << endl; 135 }