• CodeForces 1200D White Lines


    cf题面

    - Time limit

    1500 ms

    • Memory limit

      262144 kB

    解题思路

    官方题解

    1200D - White Lines

    Let's consider a single row that contains at least one black cell. If the first appearance of a black cell is at the l -th column and the last appearance of a black cell is at the r -th column, we can determine whether it becomes a white line when a certain cell ( i , j ) is clicked in O ( 1 ) , after some preprocessing. It becomes a white line if and only if a cell ( i , j ) is clicked where the row is at [ i , i + k 1 ] and j l r j + k 1 . We just need to compute l and r in advance.

    Now let's consider all n rows (not columns). First, count all rows that are already white lines before clicking. Then we count the number of white rows when the cell ( 1 , 1 ) is clicked, by applying the above method to all rows from 1 to k . Ignore the already-white rows that we counted before. So far we obtained the number of white rows when the cell ( 1 , 1 ) is clicked. From now, we slide the window. Add the k + 1 -st row and remove the 1 -st row by applying the same method to them, and we obtain the number of white rows when the cell ( 2 , 1 ) is clicked. We can repeat this until we calculate all n k + 1 cases for clicking the cells at the 1 -st column. Then we repeat the whole process for all n k + 1 columns.

    The same process can be done for counting white columns, too. Now we know the number of white rows and white columns when each cell is clicked, so we can find the maximum value among their sums.

    Time complexity: O ( n 2 )

    可以说是十分暴力了,cf上打的标签有brute force。一个优化就是把橡皮覆盖的区域一格一格地移动,这样就可以(O(1))更新边界了,(突然想到滑动窗口,虽然和这题关系不大)。还有个标签是尺取法,好像也没毛病,滑动区域,更新边界,这确实可以算简化的尺取或者双指针吧……

    另外,由于滑动区域的时候,左右滑只能快速更新空白列数,不能快速更新空白行数,上下滑同理,所以行和列分开处理,各自来一遍

    感想

    本来这题没有必要写博客的,但太兴奋了,真的。写完代码,改好CE以后,样例一遍过,半信半疑交上去,居然就AC了!

    回想暑假集训这一个月,蠢得跟啥使得,集训题的做题记录,同样是一片绿,别人的就一个AC时间,我的除了AC时间,下方全都有“-1”“-2”“-3”(失败的提交次数)……每个小错都要浪费我至少两个小时……好几次花半天时间,找到了诸如continue写成return、数组下标或者变量写错之类的错,太憋屈了…………

    源代码

    #include<cstdio>
    #include<algorithm>
    int n,k;
    const int MAXN=2e3+4;
    int u[MAXN],d[MAXN],l[MAXN],r[MAXN];
    
    int ansrow[MAXN][MAXN],anscol[MAXN][MAXN],wrow,wcol;
    
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=n;i++)
    	{
    		char s[2010];
    		scanf("%s",s+1);
    		for(int j=1;j<=n;j++)
    		{
    			if(s[j]=='B')
    			{
    				r[i]=j;
    				if(!l[i]) l[i]=j;
    				d[j]=i;
    				if(!u[j]) u[j]=i;
    			}
    		}
    	}
    	for(int i=1;i<=n;i++)
    	{
    		if(u[i]==0) wcol++;
    		if(l[i]==0) wrow++;
    	}
    	//先是列
    	for(int i=1;i+k-1<=n;i++)//对于每一行
    	{
    		for(int ii=1;ii<=k;ii++)//统计每行开头区域的答案
    			if(d[ii]&&d[ii]<=i+k-1&&u[ii]>=i) anscol[i][1]++;
    		for(int j=2;j+k-1<=n;j++)//将统计区域向右滑动
    		{
    			anscol[i][j]=anscol[i][j-1];
    			if(d[j-1]&&d[j-1]<=i+k-1&&u[j-1]>=i) anscol[i][j]--;
    			if(d[j+k-1]&&d[j+k-1]<=i+k-1&&u[j+k-1]>=i) anscol[i][j]++;
    		}
    	}
    	//然后行也来一遍
    	for(int i=1;i+k-1<=n;i++)
    	{
    		for(int ii=1;ii<=k;ii++)//统计每列开头区域的答案
    			if(r[ii]&&r[ii]<=i+k-1&&l[ii]>=i) ansrow[1][i]++;
    		for(int j=2;j+k-1<=n;j++)//将统计区域向下滑动
    		{
    			ansrow[j][i]=ansrow[j-1][i];
    			if(r[j-1]&&r[j-1]<=i+k-1&&l[j-1]>=i) ansrow[j][i]--;
    			if(r[j+k-1]&&r[j+k-1]<=i+k-1&&l[j+k-1]>=i) ansrow[j][i]++;
    		}
    	}
    	int ans=-1;
    	for(int i=1;i+k-1<=n;i++)
    	{
    		for(int j=1;j+k-1<=n;j++)
    			ans=std::max(ans,anscol[i][j]+ansrow[i][j]);
    	}
    	printf("%d
    ",ans+wcol+wrow);
    	return 0;
    }
    
    
  • 相关阅读:
    java进阶书籍推荐(不包括基础)
    js/jquery如何获取获取父窗口的元素
    jQuery检查某个元素在页面上是否存在
    H5利用pattern属性和oninvalid属性验证表单
    zTree的使用教程
    input属性disabled和readonly的区别
    CentOS 7 安装部署 cassandra作为kairosdb的数据存储
    Jenkins部署
    CentOS 7常用命令
    虚拟机 克隆:完整克隆 模式
  • 原文地址:https://www.cnblogs.com/wawcac-blog/p/11355416.html
Copyright © 2020-2023  润新知