• Luogu2435 染色【状压qwq】【轮廓线DP】


    LINK


    题目大意

    有一个 n 行 m 列的格点图,你需要给每个点上染上 k 种颜色中的一种,要求没有两个相邻点颜色相同。给定第一行与最后一行的染色,试求总染色方案数。

    思路

    暴力预处理状态暴力转移可以得到80分的高分

    这个时候司来了一句:

    不要按行转移,按块转移就A了

    于是改改改写了一个轮廓线

    就把轮廓线上的颜色信息记录下来就好了,随便转移一下


    注意终止状态也需要考虑轮廓线上的情况

    需要把最后一个位置的轮廓加上


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    typedef pair<int, int> pi;
    typedef long long ll;
    typedef double db;
    #define fi first
    #define se second
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x;
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int Mod = 376544743;
    const int N = 1e2 + 10;
    const int M = 10;
    const int K = 1 << (M << 1);
    int n, m, k;
    int s[(int)1e5 + 10][2];
    
    int add(int a, int b) {
      return (a += b) >= Mod ? a - Mod : a;
    }
    
    int mul(int a, int b) {
      return 1ll * a * b % Mod;
    }
    
    namespace Solve1 {
    void solve() {
      fu(i, 1, m) Read(s[i][0]);
      fu(i, 1, m) Read(s[i][1]);
      fu(i, 2, m) {
        if (s[i][0] == s[i - 1][0] || s[i][1] == s[i - 1][1]) {
          printf("0");
          return;
        }
      }
      fu(i, 1, m) {
        if (s[i][0] != s[i][1]) {
          if (n & 1) {
            printf("0");
            return;
          }
        } else {
          if (!(n & 1)) {
            printf("0");
            return;
          }
        }
      }
      printf("1");
    }
    }
    
    namespace Solve2 {
    vector<int> group;
    int dp[N][K];
    bool trans[8800][8800];
    void dfs(int tmp, int s) {
      if (!tmp) {
        group.push_back(s);
        return;
      }
      fu(i, 0, k - 1)
        if ((s & 3) != i) dfs(tmp - 1, (s << 2) | i);
    }
    bool check(int s1, int s2) {
      fu(i, 1, m) {
        if (!((s1 & 3) ^ (s2 & 3))) return 0;
        s1 >>= 2;
        s2 >>= 2;
      }
      return 1;
    }
    void solve() {
      fu(i, 1, m) Read(s[i][0]);
      fu(i, 1, m) Read(s[i][1]);
      int bg = 0, ed = 0;
      fu(i, 2, m) {
        if (s[i][0] == s[i - 1][0] || s[i][1] == s[i - 1][1]) {
          printf("0");
          return;
        }
      }
      fu(i, 1, m) {
        bg = (bg << 2) + s[i][0];
        ed = (ed << 2) + s[i][1];
      }
      fu(i, 0, k - 1) dfs(m - 1, i);
      fv(i, group)
        fu(j, 0, i - 1)
          if (check(group[i], group[j]))
            trans[i][j] = trans[j][i] = 1;
      int posbg = 0, posed = 0;
      fv(i, group) {
        if (group[i] == bg) posbg = i;
        if (group[i] == ed) posed = i;
      }
      dp[1][posbg] = 1;
      fu(i, 2, (n >> 1)) {
        fv(j, group) if (dp[i - 1][j]) {
          fv(k, group) if (trans[j][k]) {
            dp[i][k] = add(dp[i][k], dp[i - 1][j]);
          }
        }
      }
      dp[n][posed] = 1;
      fd(i, n - 1, ((n >> 1) + 1)) {    
        fv(j, group) if (dp[i + 1][j]) {
          fv(k, group) if (trans[j][k]) {
            dp[i][k] = add(dp[i][k], dp[i + 1][j]);
          }
        }
      }
      int ans = 0;
      fv(i, group) if (dp[n >> 1][i])
        fv(j, group) if (trans[i][j])
          ans = add(ans, mul(dp[n >> 1][i], dp[(n >> 1) + 1][j]));
      Write(ans);
    }
    }
    
    namespace Solve3 {
    int dp[2][M][K];
    void solve() {
      fu(i, 1, m) Read(s[i][0]);
      fu(i, 1, m) Read(s[i][1]);
      int bg = 0, ed = 0, up = (1 << ((m + 1) << 1)) - 1;
      fu(i, 2, m) {
        if (s[i][0] == s[i - 1][0] || s[i][1] == s[i - 1][1]) {
          printf("0");
          return;
        }
      }
      fd(i, m, 1) {
        bg = (bg << 2) + s[i][0];
        ed = (ed << 2) + s[i][1];
      }
      int ind = 0;
      dp[ind][m][bg] = 1;
      fu(i, 2, n) {
        ind ^= 1;
        memset(dp[ind], 0, sizeof(dp[ind]));
        fu(s, 0, up) if (dp[ind ^ 1][m][s])
          dp[ind][0][(s << 2) & up] = add(dp[ind][0][(s << 2) & up], dp[ind ^ 1][m][s]);
        fu(j, 1, m) {
          fu(s, 0, up) if (dp[ind][j - 1][s]) {
            fu(p, 0, k - 1) if ((((j == 1) || (((s >> ((j - 1) << 1))) & 3) != p) && ((s >> (j << 1)) & 3) != p)) {
              int nxt = (s & (up ^ (15 << ((j - 1) << 1)))) | ((p | (p << 2)) << ((j - 1) << 1));
              dp[ind][j][nxt] = add(dp[ind][j][nxt], dp[ind][j - 1][s]);
            }
          }
        }
      }
      Write(dp[ind][m][ed | (s[m][1] << (m << 1))]); // 结束状态不是ed 需要考虑最后的轮廓线状态
    }
    }
    
    int main() {
    #ifdef dream_maker
      freopen("input.txt", "r", stdin);
      freopen("output.txt", "w", stdout);
    #endif
      Read(n), Read(m), Read(k);
      if (k == 2) Solve1::solve();
      else if (m <= 0) Solve2::solve();
      else Solve3::solve();
      return 0;
    }
    
  • 相关阅读:
    监听本机tcp和udp的端口
    sysstat-----获取服务器负载历史记录
    inode索引详解
    tcpdump详解
    Windws Server 2008 R2 WEB环境配置之IIS7/IIS7.5+FastCGI+PHP 5.6.4+MYSQL+phpMyAdmin
    echo 命令
    带宽、流量、下载速度之间的换算
    windows 下解决 Time_Wait 和 CLOSE_WAIT 方法
    LNMP环境部署
    关于旅行
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9907473.html
Copyright © 2020-2023  润新知