传送门: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;
}