codeforces 1102D White Lines

题目链接: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 }

 

转载于:https://www.cnblogs.com/feiyue-1779930274/p/11346142.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值