• [20220322联考] 启程的日子


    前言

    构造题× 智商检测题√

    题目

    没有链接

    给一个 \(n\times m\) 的 01 矩阵表示目标状态,你一次操作可以加/减一个 \(n\times m\) 的 01 矩阵,问最少多少次可以达到目标状态,并给出构造方案。

    这里的加/减指的是对应位置的整数相加减,运算过程不要求值的范围在 \([0,1]\)

    \(1\le n,m\le 500.\)

    讲解

    首先我们特判掉各种特殊情况(\(n=1\)\(m=1\),答案为 \(0,1,2\))。

    考虑一种平凡情况,\(\min\{n,m\}>1\),那么答案为 \(3\),接下来讲构造方法。

    首先我们用两步 \(+\) 操作构造出这样类似于两把刷子的图形,恰好覆盖每个点 1 次。

    然后我们把目标状态是 0 的点在图上标出来:

    第三步就是把这些点用 \(-\) 操作减掉,所以我们需要把它们连起来:

    绿色点是我们为了第三步四联通而强行减掉的点,它们本应为 1,所以我们要在前两步使它们加到 2。这下梳子模型的优势就体现出来了,可以在任意点加而依然保证四联通。

    在具体实现时我们其实并不需要大费周章地去找绿色点使得红色点联通,我们只需要这样偷懒:

    也就是把中间全部都点成绿色,但是这样在 \(n=2\)\(m=2\) 的时候不适用,所以也要特判。

    时间复杂度是平方级别。

    代码

    长长长
    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 505;
    int n,m;
    char a[MAXN][MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    bool check0(){
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j)
    			if(a[i][j] == '1') return 0;
    	return 1;
    }
    int ID[MAXN][MAXN],f[MAXN*MAXN];
    int findSet(int x){if(f[x] ^ x) f[x] = findSet(f[x]);return f[x];}
    void unionSet(int x,int y){f[findSet(x)] = findSet(y);}
    bool check1(){
    	int nx = 0,ny = 0;
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j){
    			ID[i][j] = i*m+j; f[ID[i][j]] = ID[i][j];
    			if(i && a[i-1][j] == a[i][j]) unionSet(ID[i-1][j],ID[i][j]);
    			if(j && a[i][j-1] == a[i][j]) unionSet(ID[i][j-1],ID[i][j]);
    			if(a[i][j] == '1') nx = i,ny = j;
    		}
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j)
    			if(a[i][j] == '1' && findSet(ID[i][j]) != findSet(ID[nx][ny]))
    				return 0;
    	return 1;
    }
    void solve1(){
    	Put(1,'\n');
    	putchar('+');putchar('\n');
    	for(int i = 0;i < n;++ i,putchar('\n'))
    		for(int j = 0;j < m;++ j)
    			putchar(a[i][j]);
    }
    int cnt[MAXN*MAXN],st[MAXN],dx[4] = {1,-1},dy[4] = {0,0,1,-1};
    vector<int> ling[MAXN*MAXN];
    bool check2(){
    	int cnt1 = 0;
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j)
    			if(a[i][j] == '1' && findSet(ID[i][j]) == ID[i][j])
    				++cnt1;
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j)
    			if(a[i][j] == '0')
    				ling[findSet(ID[i][j])].emplace_back(ID[i][j]);
    	int win = -1;
    	for(int i = 0;i < n && win < 0;++ i)
    		for(int j = 0;j < m && win < 0;++ j)
    			if(ling[ID[i][j]].size()){
    				int tl = 0;
    				for(auto &A : ling[ID[i][j]]){
    					int x = A/m,y = A%m;
    					for(int k = 0;k < 4;++ k){
    						int tox = x+dx[k],toy = y+dy[k];
    						if(tox >= 0 && toy >= 0 && tox < n && toy < m && a[tox][toy] == '1')
    							st[++tl] = findSet(ID[tox][toy]);
    					}
    				}
    				if(!tl) continue;
    				sort(st+1,st+tl+1);
    				if(unique(st+1,st+tl+1)-st-1 == cnt1) win = ID[i][j];
    			}
    	if(win < 0) return 0;
    	Put(2,'\n');
    	putchar('+'); putchar('\n');
    	for(int i = 0;i < n;++ i,putchar('\n'))
    		for(int j = 0;j < m;++ j)
    			if(findSet(ID[i][j]) == win || a[i][j] == '1') putchar('1');
    			else putchar('0');
    	putchar('-'); putchar('\n');
    	for(int i = 0;i < n;++ i,putchar('\n'))
    		for(int j = 0;j < m;++ j)
    			if(findSet(ID[i][j]) == win) putchar('1');
    			else putchar('0');
    	return 1;
    }
    void solvenm1(){
    	int ans = 0;
    	if(n == 1){
    		for(int i = 0;i < m;++ i)
    			if(a[0][i] == '1' && (!i || a[0][i-1] == '0')) ++ans;
    		Put(ans,'\n');
    		for(int i = 0,j;i < m;i = j+1){
    			j = i;
    			if(a[0][i] == '0') continue;
    			putchar('+'); putchar('\n');
    			while(j < m-1 && a[0][j+1] == '1') ++j;
    			for(int k = 0;k < m;++ k)
    				if(i <= k && k <= j) putchar('1');
    				else putchar('0');
    			putchar('\n');
    		}
    	}
    	else {
    		for(int i = 0;i < n;++ i)
    			if(a[i][0] == '1' && (!i || a[i-1][0] == '0')) ++ans;
    		Put(ans,'\n');
    		for(int i = 0,j;i < n;i = j+1){
    			j = i;
    			if(a[i][0] == '0') continue;
    			putchar('+'); putchar('\n');
    			while(j < n-1 && a[j+1][0] == '1') ++j;
    			for(int k = 0;k < n;++ k)
    				if(i <= k && k <= j) putchar('1'),putchar('\n');
    				else putchar('0'),putchar('\n');
    		}
    	}
    }
    char pt[3][MAXN][MAXN];
    int bl[MAXN][MAXN];
    void solve(){
    	for(int opt = 0;opt < 3;++ opt)
    		for(int i = 0;i < n;++ i)
    			for(int j = 0;j < m;++ j)
    				pt[opt][i][j] = '0';
    	for(int i = 0;i < n;++ i)
    		for(int j = 0;j < m;++ j){
    			if(!j || (!(i&1) && j < m-1)) bl[i][j] = 0;
    			else bl[i][j] = 1;
    			pt[bl[i][j]][i][j] = '1';
    			if(a[i][j] == '0') pt[2][i][j] = '1';
    		}
    	if(n == 2 || m == 2){
    		for(int i = 0;i < n;++ i)
    			for(int j = 0;j < m;++ j)
    				if(a[i][j] == '1')
    					pt[bl[i][j]^1][i][j] = '1',pt[2][i][j] = '1';
    	}
    	else{
    		for(int i = 0;i < n;++ i)
    			for(int j = 1;j < m-1;++ j)
    				if(a[i][j] == '1')
    					pt[bl[i][j]^1][i][j] = '1',pt[2][i][j] = '1';
    	}
    	Put(3,'\n');
    	for(int opt = 0;opt < 3;++ opt){
    		if(opt <= 1) putchar('+');
    		else putchar('-');
    		putchar('\n');
    		for(int i = 0;i < n;++ i,putchar('\n'))
    			for(int j = 0;j < m;++ j)
    				putchar(pt[opt][i][j]);
    	}
    }
    
    int main()
    {
    //	freopen("bitbit.in","r",stdin);
    //	freopen("bitbit.out","w",stdout);
    	n = Read(); m = Read();
    	for(int i = 0;i < n;++ i) scanf("%s",a[i]);	
    	if(check0()) {Put(0,'\n');return 0;}
    	if(check1()) {solve1();return 0;}
    	if(check2()) return 0;
    	if(n == 1 || m == 1) {solvenm1();return 0;}
    	solve();
    	return 0;
    }
    
  • 相关阅读:
    JMeter性能测试中控制业务比例
    软件版本命名规范
    软件测试方法——静态测试与动态测试
    安装BugFree 3.0.4时出现的问题
    Linux下给mysql创建用户分配权限
    LoadRunner 测试脚本
    linux dd命令详解
    Linux查看CPU和内存使用情况
    Error:java: 无效的源发行版: 10
    rf接口自动化之结果校验
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/16040373.html
Copyright © 2020-2023  润新知