zoukankan      html  css  js  c++  java
  • loj 6037 「雅礼集训 2017 Day4」猜数列

    题目传送门

      传送门

    题目大意

      有一个位置数列,给定$n$条线索,每条线索从某一个位置开始,一直向左或者向右走,每遇到一个还没有在线索中出现的数就将它加入线索,问最小的可能的数列长度。

      依次从左到右考虑每一位上填的数。

      用$f_{L, a, R, b, S}$表示正在满足向右走的线索是$L$,前$a$个字符已经满足,正在满足向左走的线索是$R$,前$b$个字符还没有满足,还未被考虑的线索集合是$S$。

      主要有两种转移:

    • 填下一个字符
      • 如果两个线索下一个要填的字符相同,那么直接填
      • 如果不同则还需判断一下是否会使得另一线索不满足条件。
    • 更换线索
      • 向右走的线索是一堆类似于后缀的东西,向左走的线索是一堆类似于前缀的东西
      • 能不能在某个串的某个位置处更换某个串可以预处理出来

      loj上加了一堆常数优化卡到rk 1,估计很快就被超了。

      记得Doggu指着Claris这道题的非记忆化搜索写法给我说以后见着Claris记着%。

    Code

      1 /**
      2  * loj
      3  * Problem#6037
      4  * Accepted
      5  * Time: 1224ms
      6  * Memory: 25208k
      7  */
      8 #include <iostream>
      9 #include <cstdlib>
     10 #include <cstdio>
     11 #include <set>
     12 using namespace std;
     13 typedef bool boolean;
     14 
     15 const int N = 11;
     16 const int Lim = 1 << 10;
     17 
     18 #define last_one(__x) (__builtin_ffs(__x) - 1)
     19 
     20 int n;
     21 int len[N];
     22 int s[N][N];
     23 int exi[N][N];
     24 int can[N][N];    // L: forward, R: backward
     25 int usable[N][N];
     26 int f[N][N][N][N][1024];
     27 
     28 inline void init() {
     29     scanf("%d", &n);
     30     set<int> ss;
     31     for (int i = 0, x; i < n; i++) {
     32         int l = 0, hash_val = 0;
     33         while (~scanf("%d", &x) && x) {
     34             s[i][l++] = x;
     35             hash_val = hash_val * 10 + x;
     36         }
     37         len[i] = l, s[i][l] = 0;
     38         if (ss.count(hash_val))
     39             n--, i--;
     40         else
     41             ss.insert(hash_val);
     42     }
     43 
     44     for (int i = 0; i < n; i++)
     45         for (int j = 0; j < len[i]; j++)
     46             exi[i][j + 1] = exi[i][j] | (1 << s[i][j]);
     47 }
     48 
     49 // start at pos
     50 boolean check(int a, int pos, int b) {
     51     int *pa = s[a] + pos, *pb = s[b];
     52     while (*pa || *pb) {
     53         if (*pa == *pb)
     54             pa++, pb++;
     55         else if ((1 << *pb) & exi[a][pa - s[a]])
     56             pb++;
     57         else
     58             return false;
     59     }
     60     return true;
     61 }
     62 
     63 void upd(int& a, int b) {
     64     if (a > b)
     65         a = b;
     66 }
     67 
     68 // considering s[L][pl], s[R][pr - 1], S remained
     69 int dp(int L, int pl, int R, int pr, int S) {
     70     if (!S && pl == len[L] && !pr)
     71         return 0;
     72     int &rt = f[L][pl][R][pr][S];
     73     if (rt)
     74         return rt;
     75     rt = Lim;
     76     
     77     for (int T = S & can[L][pl], i = last_one(T); T; T -= (T & (-T)), i = last_one(T))
     78         upd(rt, dp(i, 0, R, pr, S ^ (1 << i)));
     79     if (!pr) {
     80         for (int i = 0; i < n && (S >> i); i++)
     81             if ((S >> i) & 1)
     82 //                for (int j = 0; j <= len[i]; j++)
     83 //                    if ((can[i][j] >> R) & 1)
     84 //                        upd(rt, dp(L, pl, i, j, S ^ (1 << i)));
     85                 for (int T = usable[R][i], j = last_one(T); T; T -= (T & (-T)), j = last_one(T))
     86                     upd(rt, dp(L, pl, i, j, S ^ (1 << i)));
     87     }
     88     
     89     if (pl < len[L] || pr) {
     90         int vl = s[L][pl], vr = ((pr) ? (s[R][pr - 1]) : (0));
     91         if (vl == vr)
     92             upd(rt, dp(L, pl + 1, R, pr - 1, S) + 1);
     93 //        if (pl < len[L] && _exi[R][pr] & (1 << vl))
     94         if (pl < len[L] && exi[R][pr] & (1 << vl))
     95             upd(rt, dp(L, pl + 1, R, pr, S) + 1);
     96         if (pr && exi[L][pl] & (1 << vr))
     97             upd(rt, dp(L, pl, R, pr - 1, S) + 1);
     98     }
     99 //    cerr << L << " " << pl << " " << R << " " << pr << " " << S  << " " << rt << '
    ';
    100     return rt;
    101 }
    102 
    103 inline void solve() {
    104     // forward
    105     for (int idx = 0; idx < n; idx++) {
    106         for (int pos = 0; pos <= len[idx]; pos++) {
    107             for (int ano = 0; ano < n; ano++) {
    108                 if (ano ^ idx)
    109                     can[idx][pos] |= check(idx, pos, ano) << ano;
    110             }
    111 //            cerr << can[idx][pos] << ' ';
    112         }
    113     }
    114     for (int i = 0; i < n; i++) {
    115         for (int j = 0; j < n; j++) {
    116             if (i ^ j) {
    117                 for (int pos = 0; pos <= len[j]; pos++)
    118                     if ((can[j][pos] >> i) & 1)
    119                         usable[i][j] |= (1 << pos);
    120             }
    121         }
    122     }
    123     len[n] = 0;
    124     for (int i = 0; i < N; i++) {
    125         exi[n][i] = 2046; //_exi[n][i] = 2046;
    126         can[n][i] = 2047;
    127     }
    128     int all = (1 << n) - 1, ans = Lim;
    129 //    ans = dp(n, 0, 1, len[1], all ^ 2);
    130     for (int i = 0; i < n; i++) {
    131         upd(ans, dp(n, 0, i, len[i], all ^ (1 << i)));
    132     }
    133     if (ans == Lim)
    134         puts("-1");
    135     else
    136         printf("%d
    ", ans);
    137 }
    138 
    139 int main() {
    140     init();
    141     solve();
    142     return 0;
    143 }
  • 相关阅读:
    C#.net开发 List与DataTable相互转换
    asp.net 7.分页
    PostgreSQL 创建触发器 Trigger
    PostgreSQL 的命令行工具 psql 的常用命令
    安装SQL Server DQS 和 MDS
    Ubuntu ssh-keygen 生成公钥并添加到远程服务器上
    阿里云code基础文档
    忘记本地MySQL数据库密码的解决方法
    谷歌浏览器安装jsonview
    phpstorm汉化包
  • 原文地址:https://www.cnblogs.com/yyf0309/p/10124870.html
Copyright © 2011-2022 走看看