比赛链接:
https://codeforces.com/contest/1638
C. Inversion Graph
题目大意:
给一个排列 \(p\),当 \(i < j\) 并且 \(p_i\) > \(p_j\) 时,会有一条边将这两个点相连,判断该排列中有多少个连通分量。
思路:
我们可以将排列分成两个集合 \(a\) 和 \(b\),当前面集合中的点的最大值比后面集合的最小值还要小的时候,说明前面两个集合之间有边,反之,说明出现一个新的连通分量了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define IOS() ios_base::sync_with_stdio(false);cin.tie(0);
void solve(){
int n, ans = 1;
cin >> n;
vector <int> a(n), b(n);
for (int i = 0; i < n; ++ i){
cin >> a[i];
b[i] = a[i];
}
for (int i = 1; i < n; ++ i)
a[i] = max(a[i - 1], a[i]);
for (int i = n - 2; i >= 0; -- i)
b[i] = min(b[i], b[i + 1]);
for (int i = 0; i < n - 1; ++ i)
if (a[i] < b[i + 1])
ans++;
cout << ans << "\n";
}
int main(){
IOS();
int T;
cin >> T;
while (T--)
solve();
return 0;
}
D. Big Brush
题目大意:
\(n * m\) 的矩阵,每个格子有一个颜色,有一个刷子,每刷一次可以让 \((x, y), (x + 1, y), (x, y + 1), (x + 1, y + 1)\) 变成一个颜色,问用不超过 \(n * m\) 步操作能不能刷出给出的矩阵,若能,输出刷的步骤,不能输出 -1。
思路:
反过来思考,通过 \(bfs\) 反向操作即可。最后一步刷的一定会形成一个 2 * 2 的颜色一样的矩阵,然后将这个矩阵标记一下,去找周围的前一步的操作,总共有八种情况。
每一次标记就是将操作的这一步的矩阵的全部元素改成 0,表示这个格子是特殊格子,不管是什么颜色都没有关系,因为后面一步的操作会将它覆盖掉。
代码:
#include <bits/stdc++.h>
using namespace std;
#define PII pair <int, int>
#define fi first
#define se second
const int N = 1e3 + 10;
int n, m, a[N][N];
vector < array <int, 3> > ans;
queue < PII > q;
int color(int x, int y){
for (int dx = 0; dx <= 1; dx ++ )
for (int dy = 0; dy <= 1; dy ++ )
if (a[x + dx][y + dy] != 0)
return a[x + dx][y + dy];
return 0;
}
bool judge(int x, int y){
if (x < 1 || x >= n || y < 1 || y >= m) return false;
int c = color(x, y);
for (int dx = 0; dx <= 1; dx ++ )
for (int dy = 0; dy <= 1; dy ++ )
if (a[x + dx][y + dy] != 0 && a[x + dx][y + dy] != c)
return false;
return true;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
cin >> a[i][j];
for (int i = 1; i < n; i ++ )
for (int j = 1; j < m; j ++ )
if ( judge(i, j) )
q.push( {i, j} );
while ( q.size() ){
PII t = q.front();
q.pop();
int x = t.fi, y = t.se;
if ( !color(x, y) ) continue;
ans.push_back( {x, y, color(x, y) } );
for (int dx = 0; dx <= 1; dx ++ )
for (int dy = 0; dy <= 1; dy ++ )
a[x + dx][y + dy] = 0;
for (int dx = -1; dx <= 1; dx ++ )
for (int dy = -1; dy <= 1; dy ++ ){
if (dx == 0 && dy == 0) continue;
if ( judge(x + dx, y + dy) ) q.push({x + dx, y + dy});
}
}
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
if (a[i][j]){
cout << "-1\n";
return 0;
}
reverse( ans.begin(), ans.end() );
cout << ans.size() << "\n";
for (auto [x, y, w] : ans)
cout << x << " " << y << " " << w << "\n";
return 0;
}