• CodeForces 567F DP Mausoleum


    本着只贴代码不写分析的题解是在耍流氓的原则,还是决定写点分析。

    思路很清晰,参考的官方题解,一下文字仅对题解做一个简要翻译。

    题意:

    有1~n这n个数,每个数用两次。构成一个长为2n的序列,而且要求序列满足先递增后递减(都是非严格的递增递减)。

    再给出k个约束,每个约束形如1 >= 3这种,表示序列的第一个数要不小于第三个数。

    问满足约束的合法序列有多少种。

    分析:

    首先先不考虑这些约束条件,考虑如何构造出这种序列。

    考虑两个1放置的位置,因为序列是两边小中间大,所以这两个1要么放在前面两个位置,或者后面两个位置,要么一前一后,而且只有这三种放法。

    事实上,不考虑约束条件的话,n个数能得到的合法的序列的个数为3n

    因此这些数是1~n从两边往中间放的。

    设d(L, R)表示[L, R]这个区间还没放数,满足约束条件的序列个数,则答案为d(1, 2n)

    下面考虑如何处理这些不等式:

    计算d(L, R)时,比如要放在L和L+1这两个格子,那么就考虑所有和L相关的不等式,以及和L+1相关的不等式。

    为了更清楚起见,画一个图看看:

    绿色表示已经放好数的区间,黄色表示正要放的两个格子,红色是还未放数的区间。

    那么有大小关系:绿色的数 < 黄色的数 < 红色的数,两个黄色格子的数是相等的。

    比如有不等式L >= v

    如果a[L] == a[v],那么v应该等于L + 1,表示L和v两个位置放同一个数;

    如果a[L] > a[v],那么v应该在绿色的区间表示之前已经放过数了,这样放在L的数才能比放在v的数大。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <map>
      7 #define MP make_pair
      8 using namespace std;
      9 
     10 typedef long long LL;
     11 
     12 const int maxn = 80;
     13 
     14 int n, k;
     15 
     16 vector<int> G[maxn], req[maxn];
     17 
     18 LL d[maxn][maxn];
     19 
     20 bool check(int L, int R, int l, int r)
     21 {
     22     for(int i = 0; i < G[l].size(); i++)
     23     {
     24         int v = G[l][i], t = req[l][i];
     25         if(t == -2)
     26         {
     27             if(v < L || v > R || v == r) return false;
     28         }
     29         else if(t == -1)
     30         {
     31             if(v < L || v > R) return false;
     32         }
     33         else if(!t)
     34         {
     35             if(v != r) return false;
     36         }
     37         else if(t == 1)
     38         {
     39             if(v >= L && v <= R && v != r) return false;
     40         }
     41         else
     42         {
     43             if(v >= L && v <= R) return false;
     44         }
     45     }
     46 
     47     for(int i = 0; i < G[r].size(); i++)
     48     {
     49         int v = G[r][i], t = req[r][i];
     50         if(t == -2)
     51         {
     52             if(v < L || v > R || v == l) return false;
     53         }
     54         else if(t == -1)
     55         {
     56             if(v < L || v > R) return false;
     57         }
     58         else if(!t)
     59         {
     60             if(v != l) return false;
     61         }
     62         else if(t == 1)
     63         {
     64             if(v >= L && v <= R && v != l) return false;
     65         }
     66         else
     67         {
     68             if(v >= L && v <= R) return false;
     69         }
     70     }
     71 
     72     return true;
     73 }
     74 
     75 LL dp(int L, int R)
     76 {
     77     LL& ans = d[L][R];
     78     if(ans >= 0) return d[L][R];
     79     if(L + 1 == R)
     80     {
     81         if(check(L, R, L, R)) return 1LL;
     82         return 0;
     83     }
     84 
     85     ans = 0;
     86 
     87     if(check(L, R, L, L + 1))
     88         ans += dp(L + 2, R);
     89     if(check(L, R, L, R))
     90         ans += dp(L + 1, R - 1);
     91     if(check(L, R, R - 1, R))
     92         ans += dp(L, R - 2);
     93 
     94     return ans;
     95 }
     96 
     97 int main()
     98 {
     99     scanf("%d%d", &n, &k);
    100     char eq[10];
    101     while(k--)
    102     {
    103         int u, v;
    104         scanf("%d", &u);
    105         scanf("%s", eq);
    106         scanf("%d", &v);
    107 
    108         int t;
    109         if(strcmp(eq, "<") == 0) t = -2;
    110         else if(strcmp(eq, "<=") == 0) t = -1;
    111         else if(strcmp(eq, "=") == 0) t = 0;
    112         else if(strcmp(eq, ">=") == 0) t = 1;
    113         else if(strcmp(eq, ">") == 0) t = 2;
    114         else exit(1234);
    115 
    116         if(u == v)
    117         {
    118             if(abs(t) <= 1) continue;
    119             else { puts("0"); exit(0); }
    120         }
    121 
    122         req[u].push_back(t); req[v].push_back(-t);
    123         G[u].push_back(v); G[v].push_back(u);
    124     }
    125 
    126     memset(d, -1, sizeof(d));
    127 
    128     printf("%I64d
    ", dp(1, n * 2));
    129 
    130     return 0;
    131 }
    代码君
  • 相关阅读:
    BOZJ 3551&BZOJ 3545 kruskal重构树
    [Poi2014]FarmCraft
    NOIP 2015 斗地主
    POJ 1704 Georgia and Bob
    BZOJ 1409 快速幂+欧拉定理
    最长公共子序列(LCS)
    神奇的口袋(百练2755)
    最长上升子序列(LIS)
    《Single Image Haze Removal Using Dark Channel Prior》去雾代码实现分析
    MATLAB中的nargin与varargin
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4738710.html
Copyright © 2020-2023  润新知