zoukankan      html  css  js  c++  java
  • 300iq Contest 3 C. Cells Blocking

    题意:给一个图,’.‘代表空地,’*‘代表障碍,每次能往右或者往下走。问有多少点对满足,把这两个空地堵上以后,使得从左上角(1,1)走到右下角(n,m)

    题解:预处理出从(1,1)出发,从(n,m)倒退,所能到达的点,将其他的不能达到的空地删除(删除前先统计总空地个数)。如果不能从(1,1)出发到达(n,m),直接得出答案。

    将这些点按照他们所处的斜对角线分组。

    显然,若一条对角线上只有一个空地,那这个空点和任意一个空地组合都可以,堵上整条路。直接统计这部分点的个数。

    若一条对角线上多个空地。那么如果要选其中一些空地堵住。只能选其中最边缘的两个空地。

    首先,我们忽略掉对角线上只有一个空地的情况,因为这部分的点对已经统计完了。

    对于剩下的任意两段对角线,他们最左边的两个空地,和最右边的两个空地一定是可以连通的,因为只能往右和往下走。比如如果不能从(3,1)到达(5,2),那(3,1)要成为空地一定要能到达(4,3)(或者右边别的空地)。那么(5,2)要成为空地,一定要从(2,2)到达。而如果(2,2)能够到达(5,2),(3,1)也一定能(它们的路径一定有交点)。

    所以如果一条斜线三个或更多的空地,也只能选择最左或者最右的空地堵上其中一个或两个。堵上中间的点,无论后面怎么堵,至少能从两端其中一个空地到达终点。

    1,1 1,2 1,3 1,4 1,5
    2,1 2,2 2,3 2,4 2,5
    3,1 3,2 3,3 3,4 3,5
    4,1 4,2 4,3 4,4 4,5
    5,1 5,2 5,3 5,4 5,5

    假设堵上最左边的空地,那么我们现在要枚举,堵上右下方斜线的哪些点能使得路径完全被堵上。

    我们从这条斜线剩余的次左边和最右边的两个空地出发。对于次左边的空地,如果能往下走,就尽量往下走。否则往右。最右边的空地,如果能往右走就往游走。如果在往右下走的过程中有汇合。说明我们堵上当前斜线上的这块空地也能堵死整条路。

    代码是300iq的代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m;
    char c[3005][3005];
    bool dp[3005][3005];
    bool dp2[3005][3005];
    vector<int>v[6005];
    ll cnt=0,ans=0;
    int main(){
    	ios::sync_with_stdio(false);
    	cin >> n >> m;
    	for(int i=1; i<=n ;i++){
    		for(int j=1; j<=m ;j++){
    			cin >> c[i][j];
    			dp[i][j]|=dp[i-1][j];
    			dp[i][j]|=dp[i][j-1];
    			dp[i][j]|=(i==1 && j==1);
    			dp[i][j]&=(c[i][j]=='.');
    			cnt+=(c[i][j]=='.');
    		}
    	}
    	for(int i=n; i>=1 ;i--){
    		for(int j=m; j>=1 ;j--){
    			dp2[i][j]|=dp2[i+1][j];
    			dp2[i][j]|=dp2[i][j+1];
    			dp2[i][j]|=(i==n && j==m);
    			dp2[i][j]&=(c[i][j]=='.');
    		}
    	}
    	for(int i=1; i<=n ;i++){
    		for(int j=1; j<=m ;j++){
    			if(!dp[i][j] || !dp2[i][j]) c[i][j]='*';
    			else v[i+j].push_back(i);
    		}
    	}
    	if(!dp[n][m]) return cout << cnt*(cnt-1)/2 << '
    ',0;
    	ll bh=0;
    	for(int i=2; i<=n+m ;i++){
    		if(v[i].size()==1) ans+=(cnt-(++bh));
    	}
    	for(int i=2; i<=n+m ;i++){
    		if(v[i].size()==1) continue;
    		int l=v[i][1],r=v[i].back();
    		if(l==r) ans++;
    		for(int j=i+1; j<=n+m ;j++){
    			if(c[l][j-l]!='.') l++;
    			if(c[r+1][j-r-1]=='.') r++;
    			if(l==r && v[j].size()!=1) ans++;  
    		}
    	}
    	for(int i=2; i<=n+m ;i++){
    		if(v[i].size()==1) continue;
    		int l=v[i][0],r=v[i][v[i].size()-2];
    		for(int j=i+1; j<=n+m ;j++){
    			if(c[l][j-l]!='.') l++;
    			if(c[r+1][j-r-1]=='.') r++;
    			if(l==r && v[j].size()!=1) ans++;  
    		}
    	}
    	cout << ans << '
    ';
    }
    
  • 相关阅读:
    java 的 四 个 基 本 特 性 ——封装 继承 多态 抽象
    java中的对象 方法 引用 等一些抽象的概念是什么意思呢?
    谈谈java中的并发(一)
    来说说Java中String 类的那些事情
    Alibaba SpringCloud (一) Nacos 集群环境搭建
    Window 环境下SonarQube的安装与部署
    Windows 环境下MySQL 8.0.15 安装配置指南
    Docker 入门
    Springboot中,Tomcat启动war包的流程
    SpringCloud入门(十一):Sleuth 与 Zipkin分布式链路跟踪
  • 原文地址:https://www.cnblogs.com/Ike-shadow/p/14093202.html
Copyright © 2011-2022 走看看