E - Don't Isolate Elements (atcoder.jp)
(1)题目大意
给你一个H*W的矩阵,问你让这个矩阵变成一个不孤立的矩阵的最小操作次数,如果一个地方孤立,代表四个方向的数字和他不同,每一次操作可以使一行翻转,从0-1,1-0,问你最后最小操作次数是多少?
(2)解题思路
比赛的时候没有见过这种dp,因此也没有想到dp上面去,其实在知道是dp之后就比较好做了。
考虑定义状态dp[i][j][k],当前操作的是第i行,第i-1行的操作是j,第i的操作次数是k的最小操作次数是多少。
转移方程为dp[i][j][k] = min(dp[i][j][k],dp[i - 1][p][j] + j)
最后答案就是min(dp[n][0][0],dp[n][0][1],dp[n][1][0],dp[n][1][1]);
(3)代码实现
// Problem: E - Don't Isolate Elements
// Contest: AtCoder - UNIQUE VISION Programming Contest 2022 Winter(AtCoder Beginner Contest 283)
// URL: https://atcoder.jp/contests/abc283/tasks/abc283_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e3 + 10;
int dp[N][2][2], a[N][N];
void solve()
{
int h, w;
cin >> h >> w;
rep(i, 1, h)
{
rep(j, 1, w)
{
cin >> a[i][j];
}
}
memset(dp, 0x3f, sizeof(dp));
rep(i, 0, 1)
{
rep(j, 0, 1)
{
dp[0][i][j] = 0;
}
}
auto check = [&](int i, int p, int x, int y) {
vector<int> iso(w + 1, 1);
iso[0] = 0;
rep(j, 1, w)
{
if (i - 1 >= 1 && (a[i - 1][j] ^ p) == (a[i][j] ^ x))
{
iso[j] = 0;
}
if (i + 1 <= h && (a[i + 1][j] ^ y) == (a[i][j] ^ x))
{
iso[j] = 0;
}
if (j - 1 >= 1 && (a[i][j - 1] == a[i][j]))
{
iso[j] = 0;
}
if (j + 1 <= w && (a[i][j + 1] == a[i][j]))
{
iso[j] = 0;
}
}
return (count(iso.begin(), iso.end(), 1) == 0);
};
rep(i, 1, h)
{
rep(x, 0, 1)
{
rep(y, 0, 1)
{
rep(p, 0, 1)
{
if (check(i, p, x, y))
{
dp[i][x][y] = min(dp[i][x][y], dp[i - 1][p][x] + x);
}
}
}
}
}
int ans = inf;
rep(i, 0, 1)
{
rep(j, 0, 1)
{
ans = min(ans, dp[h][i][j]);
}
}
cout << (ans == inf ? -1 : ans) << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}
F - Permutation Distance (atcoder.jp)
(1)题目大意
给你一个序列P,问你对于每一个位置i Di = min(|Pi - Pj| + |i - j|)是多少?
(2)解题思路
考虑拆开式子
Di = Pi - Pj + i - j
Di = Pj - Pi + i - j
Di = Pi - Pj + j - i
Di = Pj - Pi + j - i
我们可以用循环控制后面那个不等变量,用权值线段树维护一个不等变量
(3)代码实现
#include "bits/stdc++.h"
using namespace std;
const int N = 200010;
const int INF = 0x3f3f3f3f;
int f[N << 2], v[N << 2], ans[N];
struct node
{
int v, p;
bool operator<(const node &other) const
{
return v < other.v;
}
} a[N];
void push_up(int u)
{
f[u] = min(f[u << 1], f[u << 1 | 1]);
v[u] = min(v[u << 1], v[u << 1 | 1]);
}
void insert(int u, int l, int r, int p, int v1, int v2)
{
if (l == r)
{
f[u] = v1;
v[u] = v2;
return;
}
int mid = (l + r) >> 1;
if (p <= mid)
{
insert(u << 1, l, mid, p, v1, v2);
}
else
{
insert(u << 1 | 1, mid + 1, r, p, v1, v2);
}
push_up(u);
}
int calcf(int u, int l, int r, int s, int t)
{
if (l == s && r == t)
{
return f[u];
}
int mid = (l + r) >> 1;
if (t <= mid)
{
return calcf(u << 1, l, mid, s, t);
}
else
{
if (s > mid)
{
return calcf(u << 1 | 1, mid + 1, r, s, t);
}
else
{
return min(calcf(u << 1, l, mid, s, mid), calcf(u << 1 | 1, mid + 1, r, mid + 1, t));
}
}
}
int calcv(int u, int l, int r, int s, int t)
{
if (l == s && r == t)
{
return v[u];
}
int mid = (l + r) >> 1;
if (t <= mid)
{
return calcv(u << 1, l, mid, s, t);
}
else
{
if (s > mid)
{
return calcv(u << 1 | 1, mid + 1, r, s, t);
}
else
{
return min(calcv(u << 1, l, mid, s, mid), calcv(u << 1 | 1, mid + 1, r, mid + 1, t));
}
}
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i].v);
a[i].p = i;
}
memset(ans, 0x3f, sizeof(ans));
for (int i = 1; i <= 4 * n; i++)
{
f[i] = v[i] = INF;
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
{
ans[a[i].p] = min(ans[a[i].p], a[i].v + a[i].p + calcf(1, 1, n, 1, a[i].p));
ans[a[i].p] = min(ans[a[i].p], a[i].v - a[i].p + calcv(1, 1, n, a[i].p, n));
insert(1, 1, n, a[i].p, -a[i].v - a[i].p, -a[i].v + a[i].p);
}
for (int i = 1; i <= n; i++)
{
a[i].v = -a[i].v;
}
for (int i = 1; i <= 4 * n; i++)
{
f[i] = v[i] = INF;
}
sort(a + 1, a + 1 + n);
for (int i = 1; i <= n; i++)
{
ans[a[i].p] = min(ans[a[i].p], a[i].v + a[i].p + calcf(1, 1, n, 1, a[i].p));
ans[a[i].p] = min(ans[a[i].p], a[i].v - a[i].p + calcv(1, 1, n, a[i].p, n));
insert(1, 1, n, a[i].p, -a[i].v - a[i].p, -a[i].v + a[i].p);
}
for (int i = 1; i <= n; i++)
{
printf("%d ", ans[i]);
}
return 0;
}