771d2题解加补题【更新】

传送门:Dashboard - Codeforces Round #771 (Div. 2) - Codeforces

题意:通过旋转一个连续的子段,得到字典序最小的序列

解:找到第一个a[i]!=i的位置l,然后再找到值为i的位置r,颠倒[l, r]

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y); for(int i=x;i<=y;i++)
#define dec(i,x,y); for(int i=x;i>=y;i--)
#define int long long
#define Int __int128
#define INF 0x3f3f3f3f
const int maxn=2e5+105;
int a[505], b[505];
main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
    cin >> t;
    while(t--){
    	int n, l = 0, r = 0, k = 0;
    	bool fg = true;
    	cin >> n;
    	rep(i, 1, n){
    		cin >> a[i];
    		if(a[i] != i && fg){
    			l = i;
    			fg = false;
			}
			if(a[i] == l){
				r = i;
			}
		}
		reverse(a + l, a + r + 1);
		rep(i, 1, n) cout << a[i] << " ";
		cout << "\n";
	}
    return 0;
}

 题意:如果a[i]和a[i + 1]满足a[i] + a[i + 1] 为奇数,则可以交换,可以经过任意次交换,问是否可以得到单调不减的数组

解:相邻两数奇偶不同,无论大小总可以变为有序,但如果奇偶相同的无序,是无法变为有序,则只要看原数组中奇数是否有序,偶数是否有序即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y); for(int i=x;i<=y;i++)
#define dec(i,x,y); for(int i=x;i>=y;i--)
#define int long long
#define Int __int128
#define INF 0x3f3f3f3f
const int maxn=2e5+105;
int ji[maxn], ou[maxn];
main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
    cin >> t;
    while(t--){
    	int n, x, c1 = 0, c2 = 0;
    	cin >> n;
    	rep(i, 1, n){
    		cin >> x;
    		if(x % 2 == 1) ji[++c1] = x;
    		else ou[++c2] = x;
		}
		bool fg = true;
		rep(i, 1, c1 - 1){
			if(ji[i] > ji[i + 1])fg = false;
		}
		rep(i, 1, c2 - 1){
			if(ou[i] > ou[i + 1])fg = false;
		}
		if(fg) cout << "YES\n";
		else cout << "NO\n";
	}
    return 0;
}

 题意:对于每一个结点,自己和自己是联通的,然后存在逆序对,即可加一条边,使之相互连通,最后有几个联通块

解:一开始想的是并查集加线段树,后来想想时间复杂度有点高。换了个思路,从前往后遍历,如果新加的一个数,大于前面数中最大,就不会与前树存在逆序数对,就会出现一个新的联通块,加入即可,如果小于的话,就会出现一个问题,这个数就有可能作为中间数,将前面的几个大数链接起来,这时就要找到大于等于这个数的最小数x,然后将大于等于x的数都合并成一个最大的数

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y); for(int i=x;i<=y;i++)
#define dec(i,x,y); for(int i=x;i>=y;i--)
#define int long long
#define Int __int128
#define INF 0x3f3f3f3f
const int maxn=2e5+105;
int a[maxn], b[maxn];
main(){
	int t;
    cin >> t;
    while(t--){
    	int n;
    	cin >> n;
    	rep(i, 1, n) cin >> a[i];
		int cnt = 0, mx = 0, ans = 0;
		rep(i, 1, n){
			if(a[i] >= mx){
				b[++cnt] = a[i];
				mx = a[i];
				ans++;
			} 
			else{
				int id = lower_bound(b + 1, b + cnt + 1, a[i]) - b;
				if(b[id] > a[i] && b[id] < mx){
					ans -= (cnt - id + 1) - 1;
					cnt = id;
					b[id] = mx;
				} 
			}
		}
		cout << ans << "\n";
	}
    return 0;
}

题意:找到一种覆盖方案,得到题中给出的数组

解:倒过来寻找,最后覆盖上去的肯定是2*2的,并且前面是什么样的对它不构成影响,所以我们可以用bfs找解,每次找到合理的2*2区间,更新一下地图

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y); for(int i=x;i<=y;i++)
#define dec(i,x,y); for(int i=x;i>=y;i--)
#define int long long
#define Int __int128
#define INF 0x3f3f3f3f
#define lson(x) x << 1
#define rson(x) x << 1 | 1
#define FI first
#define SE second
#define MP make_pair
#define pb push_back
#define all(x) x.begin(), x.end()
typedef pair<int, int> PII;
const int maxn=2e5+105;
int mp[1005][1005], n, m;
bool fre[1005][1005], vis[1005][1005];
vector<array<int, 3>> ans;
queue<array<int,3>> q;
const int dx[]={-1,-1,-1,0,0,0,1,1,1};
const int dy[]={-1,0,1,-1,0,1,-1,0,1};
int check(int x,int y){
	int las=-1;
	for(int i=x;i<=x+1;i++){
		for(int j=y;j<=y+1;j++){
			if(fre[i][j])continue;
			if(las == -1)las=mp[i][j];
			else if(mp[i][j]!=las)return -1;
		}
	}
	return ~las?las:1;
}
main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin >> n >> m;
	rep(i, 1, n){
		rep(j, 1, m){
			cin >> mp[i][j];
		} 
	} 
	rep(i, 1, n - 1){
		rep(j, 1, m - 1){
			if(check(i, j) != -1){
				vis[i][j] = 1, q.push({i,j,mp[i][j]});
			}
		} 
	} 
	while(!q.empty()){
		auto [x, y, _] = q.front();
		q.pop();
		ans.pb({x, y, _});
		fre[x][y] = fre[x][y + 1] = fre[x + 1][y] = fre[x + 1][y + 1] = 1;
		for(int d = 0; d < 9; d++){
			int fx = x + dx[d], fy = y + dy[d];
			if(fx >= 1 && fx < n && fy >= 1 && fy < m && !vis[fx][fy]){
				int t = check(fx, fy);
				if(t != -1){
					vis[fx][fy] = 1;
					q.push({fx, fy, t});
				}
			}
		}
	}
	if(ans.size() != (n - 1) *(m - 1)){
		cout << "-1\n";
		return 0;
	} 
	cout << ans.size() << "\n";
	reverse(all(ans));
	for(auto [x, y, z] : ans){
		cout << x << " " << y << " " << z << "\n";
	}
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值