Forever Young

「考前日志」11.17

总结

最近真的很不对劲

打不起精神头来

而且电脑还巨卡

一天做不了几道题

挺压抑的

上一次这种情况是在三月份了……

我该怎么办啊

⑨⑨⑤⑧

今日已完成

  • AcWing291 蒙德里安的梦想

    状压DP。
    以行数以及此行的形态为状态。
    \(f_{i,j}\) 表示前 \(i\) 行,第 \(i\) 行形态为 \(j\) 时的方案总数。
    此处 \(j\) 是一个用十进制整数记录的 \(m\) 位二进制数。
    如果 \(j\) 二进制下当前位置为 \(1\),说明该位置为某个小长方形的上半部分,下一行的当前位置一定要放下半部分(即为 \(0\))。
    如果为 \(0\) 表示其他情况,对下一行的形态无影响,但要保证连续的 \(0\) 的个数为偶数个。
    对于当前行 \(i\) 的形态 \(j\),可以由上一行 \(i- 1\) 的形态 \(k\) 转移过来当且仅当:

    • 当前行的形态 \(j\) 与上一行的形态 \(k\) 的与运算结果为 \(0\)
      这样保证了上一行形态中为 \(1\) 的位对应的当前位一定为 \(0\),满足上述条件。
    • \(j\)\(k\) 的按位或运算的二进制表示中连续 \(0\) 的个数为偶数个。
      这样也就说明\(j\)\(k\) 的二进制表示中连续 \(0\) 的个数为偶数个。

    预处理合法(即连续 \(0\) 为偶数)的状态,然后 dp 即可。

    \[f_{i,j}=\sum\limits_{j\&k=0且j|k合法}f_{i-1,k} \]

    #include <map>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ll long long
    using namespace std;
    
    const int A = 1e5 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar(); int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, m;
    bool ok[A];
    ll f[12][1 << 11];
    
    int main() {
      while (cin >> n >> m) {
        if (n == 0 && m == 0) return 0;
        memset(f, 0, sizeof(f));
        for (int i = 0; i < (1 << m); i++) {
          bool cnt = 0, has_odd = 0;
          for (int j = 0; j < m; j++) 
            if (i >> j & 1) has_odd |= cnt, cnt = 0;
            else cnt ^= 1;
          ok[i] = !(has_odd | cnt);
        }
        f[0][0] = 1;
        for (int i = 1; i <= n; i++) {
          for (int j = 0; j < (1 << m); j++) {
            for (int k = 0; k < (1 << m); k++) 
              if ((j & k) == 0 && ok[j | k]) 
                f[i][j] += f[i - 1][k];
          }
        }
        cout << f[n][0] << '\n';
      }
    }
    
  • AcWing289 环路运输

    环形DP
    还是断环成链的操作
    把环拆开,复制一倍,形成一个长度为 \(2n\) 的链
    那么就是要求最大的 \(1\le{i,j}\le{2n}\)\({i-j}\le{\dfrac{n}{2}}\)\(i,j\)\(a_i+a_j+i-j\) 的最大值
    可以用单调队列优化,做到 \(O(n)\) 的复杂度

    #include <map>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 2e6 + 11;
    const int B = 1e6 + 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar(); int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    int n, head, tail, len, a[A], q[A], ans;
    
    int main() {
      n = read();
      for (int i = 1; i <= n; i++) a[i] = read(), a[i + n] = a[i];
      len = n / 2, head = 1, tail = 0;
      q[++tail] = a[1];
      for (int i = 2; i <= n * 2; i++) {
        while (head <= tail && q[head] < i - len) head++;
        ans = max(ans, i + a[i] + a[q[head]] - q[head]);
        while (head <= tail && a[q[tail]] - q[tail] < a[i] - i) tail--;
        q[++tail] = i;
      }
      cout << ans << '\n';
      return 0;
    }
    
  • 牛客编程巅峰赛S2第2场 - 钻石&王者T1
    函数式编程难受,机房电脑性能辣鸡

    class Solution {
    public:
        /**
         * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
         *
         * @param n long长整型 表示标准完全二叉树的结点个数
         * @return long长整型
         */
        long long tree4(long long n) {
            // write code here
            long long mod = 998244353;
            long long base = 0, x = 0, ans = 0;
            while (x + (1 << base) <= n) {
                long long now = x + (1 << base);
                ans = ans + (1ll * now * (now + 1) / 2 % mod - 1ll * x * (x + 1) / 2 % mod + mod) % mod * (base + 1);
                ans = ans % mod;
                x = now, base++;
            }
            if (x == n) return ans;
            ans += (1ll * n * (n + 1) / 2 % mod - x * (x + 1) / 2 % mod + mod) % mod * (base + 1) % mod;
            ans %= mod;
            return ans;
        }
    };
    
  • 牛客编程巅峰赛S2第2场 - 钻石&王者T2

    函数式编程难受,机房电脑性能辣鸡,不会写高精/kk

    class Solution {
      public:
        /**
         * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
         * 返回最大和的字符串
         * @param x string字符串 即题目描述中所给字符串
         * @param k int整型 即题目描述中所给的k
         * @return string字符串
         */
        string Maxsumforknumers(string x, int k) {
          int vis[100] = { 0 };
          int n = x.size(), ans[100001] = { 0 }, len = 0;
          string s;
          for (int i = 0; i < n; i++) vis[x[i] - '0']++;
          for (int i = 1; i <= n - k + 1; i++) {
            int we = 0;
            for (int j = 9; j >= 0; j--)
              if (vis[j]) {
                we = j, vis[we]--;
                break;
              }
            ans[i] = we;
          }
          len = n - k + 1;
          reverse(ans + 1, ans + len + 1);
          int we = 0;
          for (int j = 0; j <= 9; j++)
            while (vis[j]) {
              vis[j]--, we = j;
              int po = 1;
              ans[po] += j;
              while (ans[po] >= 10) ans[po] -= 10, po++, ans[po]++, len = max(len, po);
            }
          reverse(ans + 1, ans + len + 1);
          for (int i = 1; i <= len; i++) s += ans[i] + '0';
          return s;
        }
    };
    
  • AcWing292 炮兵阵地

    \(f_{i,j,k}\) 表示已经摆完前 \(i\) 行,且所有摆放的炮兵之间不能相互攻击到,每个炮兵都不在山地上,第 \(i\) 行的状态为 \(j\),第 \(i-1\) 行的状态为 \(k\) 的方案数。

    因为第 \(i\) 行和第 \(i-1\) 行的状态已经确定了,但是当前阶段还和第 \(i-2\) 行的状态有关,所以要枚举第 \(i-2\) 行的状态,记为 \(u\)

    什么时候状态是合法的呢?

    • \(j,k,u\) 三者表示的状态无交集。
    • \(i\) 行的炮兵没有摆放到山地上。
    • \(i\) 行的炮兵两两之间的距离\(\ge2\)

    显然满足上述条件的状态就是合法的。

    转移: \(f_{i,j,k}=f_{i-1,j,u}+sum_i\)

    其中 \(sum_i\) 表示第 \(i\) 行可以摆放的炮兵的个数。

    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    const int A = 111;
    const int B = 11;
    const int S = 1 << 11;
    const int mod = 1e9 + 7;
    const int inf = 0x3f3f3f3f;
    
    inline int read() {
      char c = getchar();
      int x = 0, f = 1;
      for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
      for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
      return x * f;
    }
    
    vector <int> sta;
    int n, m, g[A], sum[S], f[2][S][S];
    
    bool check(int s) {
      for (int i = 0; i < m; i++) 
        if (((s >> i) & 1) && (((s >> (i + 1)) & 1) || (s >> (i + 2) & 1)))
          return false;
      return true;
    }
    
    int count(int x) {
      int cnt = 0;
      while (x) {
        cnt += x & 1;
        x >>= 1;
      }
      return cnt;
    }
    
    int main() {
      n = read(), m = read();
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
          char c;
          cin >> c;
          if (c == 'H') g[i] += (1 << j);
        }
      }
      for (int i = 0; i < 1 << m; i++) {
        if (check(i)) {
          sta.push_back(i);
          sum[i] = count(i);
        }
      }
    //  cout << sta.size() << '\n';
      for (int i = 0; i < n + 2; i++) {
        for (int k = 0; k < sta.size(); k++)
          for (int j = 0; j < sta.size(); j++)
            for (int u = 0; u < sta.size(); u++) {
              int a = sta[u], b = sta[j], c = sta[k];
              if ((a & b) || (a & c) || (b & c)) continue;
              if (g[i] & c) continue;
              f[i & 1][k][j] = max(f[i & 1][k][j], f[i - 1 & 1][j][u] + sum[c]);
            }
      }
      cout << f[n + 1 & 1][0][0] << '\n';
    }
    
posted @ 2020-11-17 16:13  Loceaner  阅读(111)  评论(0编辑  收藏  举报