音无结弦之时,天使跃动之心。立于浮华之世,奏响天籁之音。.|

次林梦叶

园龄:3年3个月粉丝:21关注:2

AtCoder Beginner Contest 283

《E - Don't Isolate Elements》

dp

 

 

 刚开始拿到这道题时,我总是在想:第一行翻不翻转对下面情况的影响,在什么情况下要反转,等一系列情况

最后我发现:这些情况不如我可以利用状态转移来实现,于是我朝着dp方向想。

一开始我设置的dp是dp[i][j]:在第i-1行即以上行都合法,而且使第i行也合法同时第i行翻不翻转的状态为j的最小操作次数

但是这样设置我下面就面临了问题:

  1.第i行的合法性与第i-1行和第i+1行是相关的,

  2.既然第i行的合法性与第i+1行是相关的,我又如何能够保证在第i+1还没被算出来之前,第i行是能够提前被算出来的呢?

  即我状态转移不知道写。

  3.我如何确定合法性?

解决:

  dp[i]...:首先这里我便要重新定义:既然要知道第i+1行的状态才能知道第i行合法性,那便i表示保证第i-1以及以上行的合法性

,但是不保证第i行的合法性。

  在状态转移的过程中,比如从第i-1行转移到第i行该如何转移?

  因为dp[i-1]...不保证第i-1行合法性,我必须枚举第i行的状态和第i-1行的状态,以及要知道第i-2行的状态才能知道,第i-1行到底合不合法

于是:

  dp[i][j][k]:表示保证第i-1以及以上行的合法性,并且第i-1行的状态为j,第i行的状态为k的最小操作次数

如果第i-1行在第i-2行状态为u,第i-1行状态为j,第i行状态为k的情况下,是合法的,那么进行状态转移:

k只有0,1两个状态

dp[i][j][k]=min(dp[i][j][k],dp[i-1][u][j]+k)

如何判断是否合法看check()函数

复制代码
 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 const int INF = 0x3f3f3f3f;
 6 const int N = 1005;
 7 // dp[i][j][k]:表示在第i行,确保第i-1行即以上的行都是合法的情况下
 8 // 到达第i行状态是k,第i-1行状态是j的情况的最小操作数;
 9 int dp[N][2][2], n, m;
10 int a[N][N];
11 // 在第i-2行状态为u,第i-1行状态为j,第i行状态为k的情况下,第i-1行是否合法
12 bool check(int u, int j, int k, int h)
13 {
14     for (int i = 1; i <= m; i++)
15     {
16         int ns = j ? !a[h][i] : a[h][i];
17         int os;
18         if (h - 1 >= 1)
19         {
20             os = u ? !a[h - 1][i] : a[h - 1][i];
21             if (ns == os)
22                 continue;
23         }
24         if (i + 1 <= m)
25         {
26             os = j ? !a[h][i + 1] : a[h][i + 1];
27             if (ns == os)
28                 continue;
29         }
30         if (h + 1 <= n)
31         {
32             os = k ? !a[h + 1][i] : a[h + 1][i];
33             if (ns == os)
34                 continue;
35         }
36         if (i - 1 >= 1)
37         {
38             os = j ? !a[h][i - 1] : a[h][i - 1];
39             if (ns == os)
40                 continue;
41         }
42         return false;
43     }
44     return true;
45 }
46 int main()
47 {
48     cin >> n >> m;
49     for (int i = 1; i <= n; i++)
50         for (int j = 1; j <= m; j++)
51             scanf("%d", &a[i][j]);
52     memset(dp, 0x3f, sizeof(dp));
53     dp[1][0][0] = 0;
54     dp[1][1][0] = 0;
55     dp[1][0][1] = 1;
56     dp[1][1][1] = 1;
57     // 0代表不反转,1代表反转
58     for (int i = 2; i <= n; i++)
59         // 第i-1行状态:
60         for (int j = 0; j <= 1; j++)
61             // 第i-2行状态:
62             for (int u = 0; u <= 1; u++)
63                 // 第i行状态:
64                 for (int k = 0; k <= 1; k++)
65                 {
66                     if (check(u, j, k, i - 1))
67                         dp[i][j][k] = min(dp[i][j][k], dp[i - 1][u][j] + k);
68                 }
69     int ans = INF;
70     for (int i = 0; i <= 1; i++)
71         for (int j = 0; j <= 1; j++)
72             for (int k = 0; k <= 1; k++)
73             {
74                 if (check(i, j, k, n))
75                     ans = min(ans, dp[n][i][j]);
76             }
77     if (ans >= INF)
78         cout << -1;
79     else
80         cout << ans;
81     return 0;
82 }
复制代码

 《F - Permutation Distance 》

偏序问题

 

来自大佬博客:https://www.cnblogs.com/Lanly/p/17003594.html

 

 

 可以看出其是与逆序对这样的二维偏序问题很像

https://www.cnblogs.com/cilinmengye/p/17008988.html

只是逆序对,用持久化数据结构维护的是区间内数的个数

这里我们要维护的是区间数的最小值,用线段树维护:

复制代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 2 * 1e5 + 5, INF = 0x3f3f3f3f;
struct tree
{
    int k1, k2;
    int l, r;
} tr1[N * 4], tr2[N * 4];
void pushup1(int u)
{
    tr1[u].k1 = min(tr1[u << 1].k1, tr1[u << 1 | 1].k1);
    tr1[u].k2 = min(tr1[u << 1].k2, tr1[u << 1 | 1].k2);
}
void pushup2(int u)
{
    tr2[u].k1 = min(tr2[u << 1].k1, tr2[u << 1 | 1].k1);
    tr2[u].k2 = min(tr2[u << 1].k2, tr2[u << 1 | 1].k2);
}
void build(struct tree tr[], int x, int l, int r)
{
    tr[x].k1 = tr[x].k2 = INF;
    if (l == r)
    {
        tr[x].l = tr[x].r = l;

        return;
    }
    tr[x].l = l, tr[x].r = r;
    int mid = (l + r) >> 1;
    build(tr, x << 1, l, mid);
    build(tr, x << 1 | 1, mid + 1, r);
}
void modify1(int u, int x, int p, int i)
{
    if (tr1[u].l == x && tr1[u].r == x)
    {
        tr1[u].k1 = -(p + i);
        tr1[u].k2 = -(-p + i);
        return;
    }
    int mid = (tr1[u].l + tr1[u].r) >> 1;
    if (x <= mid)
        modify1(u << 1, x, p, i);
    else
        modify1(u << 1 | 1, x, p, i);
    pushup1(u);
}
void modify2(int u, int x, int p, int i)
{
    if (tr2[u].l == x && tr2[u].r == x)
    {
        tr2[u].k1 = -(p - i);
        tr2[u].k2 = -(-p - i);
        return;
    }
    int mid = (tr2[u].l + tr2[u].r) >> 1;
    if (x <= mid)
        modify2(u << 1, x, p, i);
    else
        modify2(u << 1 | 1, x, p, i);
    pushup2(u);
}
int query1(struct tree tr[], int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].k1;
    int ans = INF;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if (l <= mid)
        ans = min(ans, query1(tr, u << 1, l, r));
    if (r > mid)
        ans = min(ans, query1(tr, u << 1 | 1, l, r));
    return ans;
}
int query2(struct tree tr[], int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r)
        return tr[u].k2;
    int ans = INF;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if (l <= mid)
        ans = min(ans, query2(tr, u << 1, l, r));
    if (r > mid)
        ans = min(ans, query2(tr, u << 1 | 1, l, r));
    return ans;
}
int ps[N], n;
int ans[N];
int main()
{
    cin >> n;
    build(tr1, 1, 1, n);
    build(tr2, 1, 1, n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &ps[i]);
    for (int i = 1; i <= n; i++)
    {
        int p = ps[i];
        ans[i] = min(p + i + query1(tr1, 1, 1, p - 1), -p + i + query2(tr1, 1, p + 1, n));
        modify1(1, p, p, i);
    }
    for (int i = n; i >= 1; i--)
    {
        int p = ps[i];
        ans[i] = min(min(ans[i], p - i + query1(tr2, 1, 1, p - 1)), -p - i + query2(tr2, 1, p + 1, n));
        modify2(1, p, p, i);
    }
    for (int i = 1; i <= n; i++)
        cout << ans[i] << " ";
    cout << endl;
    return 0;
}
复制代码

 

本文作者:次林梦叶

本文链接:https://www.cnblogs.com/cilinmengye/p/17008799.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   次林梦叶  阅读(49)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起