• USACO 2017 FEB Platinum nocross DP


      题目大意

        上下有两个长度为n、位置对应的序列A、B,其中数的范围均为1~n。若abs(A[i]-B[j]) <= 4,则A[i]与B[j]间可以连一条边。现要求在边与边不相交的情况下的最大的连边数量。n <= 10^5。

      在Gold里,此题的数据范围是1000,我们完全可以用简单的最长公共连续子序列的DP方法来做。

      范围大了之后,可以观察到对于一个数A[i],它所能转移的状态最多只有9个,那么就可以顺序扫描A数组,设F[i][j]表示当前连得最后一条边为(A[i],B[to[i][j]])的最优解。to[i][j]即A[i]能转移到的B[i]的位置(顺序从小到大)。建立一棵线段树,表示最后连的边中的数B在B数组的位置时,所能得到的最优解。F[i][j]就可以直接logn查询,logn把F[i][j]更新到线段树中。

      

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    const int maxn = 100005;
    int n, a[maxn], b[maxn];
    int f[maxn][12], cnt[maxn], to[maxn];
    int adj[maxn][12];
    struct Tree
    {
        int maxv[maxn*4];
        Tree()
        {
            memset(maxv, 0, sizeof(maxv));
        }
        void pushup(int rt)
        {
            maxv[rt] = max(maxv[rt<<1], maxv[(rt<<1)+1]);
        }
        void update(int rt, int l, int r, int p, int d)
        {
            if (l == r)
            {
                maxv[rt] = max(maxv[rt], d);
                return ;
            }
            int mid = (l+r)>>1;
            if (p <= mid)
                update(rt<<1, l, mid, p, d);
            else
                update((rt<<1)+1, mid+1, r, p, d);
            pushup(rt);
        }
        int query(int rt, int l, int r, int L, int R)
        {
            if (L <= l && r <= R)
                return maxv[rt];
            int mid = (l+r)>>1, ret = 0;
            if (L <= mid)
                ret = max(ret, query(rt<<1, l, mid, L, R));
            if (R > mid)
                ret = max(ret, query((rt<<1)+1, mid+1, r, L, R));
            return ret;
        }
    }T;
    
    int main()
    {
        freopen("nocross.in", "r", stdin);
        freopen("nocross.out", "w", stdout);
        scanf("%d", &n);
        for (int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        for (int i = 1; i <= n; ++i)
            scanf("%d", &b[i]), to[b[i]] = i;
        for (int i = 1; i <= n; ++i)
        {
            int l = a[i]-4, r = a[i]+4;
            if (l < 0) 
                l = 1;
            if (r > n)
                r = n;
            cnt[i] = 0;
            for (int j = l; j <= r; ++j)
                adj[i][++cnt[i]] = to[j];
            sort(adj[i]+1, adj[i]+cnt[i]+1);
        }
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= cnt[i]; ++j)
                if (adj[i][j]-1 >= 1)
                    f[i][j] = T.query(1, 1, n, 1, adj[i][j]-1)+1;
                else
                    f[i][j] = 0;
            for (int j = 1; j <= cnt[i]; ++j)
                if (adj[i][j]-1 >= 1)
                    T.update(1, 1, n, adj[i][j], f[i][j]);
        }
        printf("%d
    ", T.maxv[1]);
        return 0;
    }

      

    Nothing is impossible!
  • 相关阅读:
    Unique constraint on single String column with GreenDao2
    Unique constraint on single String column with GreenDao
    将String转换成InputStream
    TypeError: unsupported operand type(s) for +: 'float' and 'str'
    Could not find private key file: AuthKey_NCD8233CS5.p8
    【Winows10】添加桌面小工具(在桌面显示时钟,日历)
    【Windows10】禁用开机启动项
    SQL如何查询出某一列中不同值出现的次数?
    使用 管理项目依赖
    Warning: Python 3.6 was not found on your system…
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6403370.html
Copyright © 2020-2023  润新知