【codechef】Chef and the Number Sequence(构成最长公共子序列为L的可能性)

来源:互联网 发布:什么是淘宝上下架时间 编辑:程序博客网 时间:2024/05/19 15:21

大厨拥有一个长度为 N 的序列 A,其中的每个元素都是 1 到 K 之间的整数(包括 1 和 K)。现在大厨想要得到到另一个序列 B,它的长度与 A 同为 N,而且每个元素也都是 1 到 K 之间的整数(同样包括 1 和 K)。大厨要求序列 A 和序列 B 的最长公共子序列的长度恰好为 L。请你求出有多少个序列 B 可以满足大厨的要求。由于答案可能非常大,请输出答案对 109 + 7 取模之后的结果。

输入格式

输入数据第一行包含一个整数 T,表示数据组数。接下来是 T 组数据。每组数据的第一行包含三个以空格隔开的整数 N、K,和 L。每组数据的第二行包含 N 个整数 A1, A2, . . . , AN,以空格隔开。

输出格式

对于每组数据,输出一行,包含一个整数,即满足要求的 B 序列的方案数对 109 + 7 取模之后的结果。数据范围• 1 ≤ T ≤ 10• 1 ≤ N, K ≤ 16• 1 ≤ L ≤ N• 序列 A 中的每个元素都是 1 到 K 之间的整数(包括 1 和 K)

Constraints

  • 1 ≤ T ≤ 10
  • 1 ≤ N,K ≤ 16
  • 1 ≤ L ≤ N
  • The sequence A consists of integers between 1 and K (both inclusive).

Example

Input:22 2 11 23 3 21 2 2Output:311

第一个样例:满足要求的序列 B 一共三种:[1, 1]、[2, 2],和 [2, 1]。这三个序列与序列 A 的最长公共子序列长度均为 1。注意 [1, 2] 不是一个满足要求的序列,因为它与序列 A 的最长公共子序列长度为 2。第二个样例:满足要求的序列 B 一共 11 种:[1, 1, 2]、[1, 2, 1]、[1, 2, 3]、[1, 3, 2]、[2, 1, 2]、[2, 2, 1]、[2, 2, 2]、[2, 2, 3]、[2, 3, 2]、[3, 1, 2],和 [3, 2, 2]。说明我们认为两个序列不同,当且仅当两个序列有至少一个位置上的元素值不同。

https://www.codechef.com/COOK61/problems/SEQLCS

————————————————————————

是一道不错的难题。next[d][j]表示在构造我们要求的其中一种数列时向末位插入数字j(1<=j<=k)之后最长公共子序列变化。d和mask都是二进制,表示取了A数组的某几位组成最长公共子序列。dp[i][d]表示距离构成B数组还差i位,还差d的二进制表示的几位最长公共子序列。

为了避免重复算,比如1 2 2,避免算两次1 2,或者算两次2,中间那一段难懂的代码就是完成这个操作。所以还是以1 2 2为例,二进制d取3和取5是一样的,取2和取4也是一样的,因此每次都要把这些一样的情况的mask归成一样的,这样在算dp时才会只算一次。

#include <bits/stdc++.h>using namespace std; const int N = 18;const int M = (1 << 16) + 2;const int MOD = 1000000007; int dp[N][M], next[M][N], a[N], oldLCS[N], newLCS[N];int t, n, k, l, i, j, d, res; int main() {   // freopen("input.in", "r", stdin);   // freopen("output.out", "w", stdout);   scanf("%d", &t);   while (t--) {      scanf("%d %d %d", &n, &k, &l);       for (i = 1; i <= n; ++i) {         scanf("%d", a + i);      }       memset(dp, 0, sizeof dp);       for (d = 0; d < (1 << n); ++d) {         oldLCS[0] = 0;         for (j = 0; j < n; ++j) {            oldLCS[j + 1] = oldLCS[j] + ((d >> j) & 1);         }         for (j = 1; j <= k; ++j) {            newLCS[0] = 0;            for (i = 1; i <= n; ++i) {               if (a[i] == j) {                  newLCS[i] = oldLCS[i - 1] + 1;               } else {                  newLCS[i] = max(oldLCS[i], newLCS[i - 1]);               }            }            int mask = 0;            for (i = 1; i <= n; ++i) {               if (newLCS[i] > newLCS[i - 1]) {                  mask += (1 << (i - 1));               }            }            next[d][j] = mask;//          cout<<"// "<<d<<" "<<j<<" "<<mask<<endl;         }      }      dp[0][0] = 1;      for (i = 0; i < n; ++i) {         for (d = 0; d < (1 << n); ++d) {            if (dp[i][d] > 0) {            cout<<i<<" "<<d<<endl;               for (j = 1; j <= k; ++j) {                  dp[i + 1][next[d][j]] += dp[i][d];                  dp[i + 1][next[d][j]] %= MOD;               }            }         }      }      res = 0;      for (d = 0; d < (1 << n); ++d) {         if (__builtin_popcount(d) == l) {            res = res + dp[n][d];            if (res >= MOD) res -= MOD;         }      }      printf("%d\n", res);   }   return 0;}                       
#include <bits/stdc++.h>using namespace std; #define pb push_back#define mp make_pair#define REP(i, n) for (int i = 0; i < (int)(n); ++i)typedef long long LL;typedef pair<int, int> PII; int tt;int n, k, l;int a[16], d[1 << 16], nd[1 << 16];const int MOD = 1e9 + 7;int bc[1 << 16]; inline void modAdd(int &x, int y) {    x += y;    if (x >= MOD) x -= MOD;} int f[17], g[17];int t[1 << 16][16]; int main() {    //freopen("input.txt", "r", stdin);    REP(i, 1 << 16) bc[i] = __builtin_popcount(i);    scanf("%d", &tt);    REP(test, tt) {        scanf("%d%d%d", &n, &k, &l);        REP(i, n) scanf("%d", a + i), --a[i];        int MX = 1 << n;        memset(d, 0, sizeof d);        d[0] = 1;        REP(mask, MX) {            int c = 0;            f[0] = 0;            REP(i, n) {                if (mask & (1 << i)) ++c;                f[i + 1] = c;             }            REP(j, k) {                REP(q, n) {                    if (a[q] == j) {                        g[q + 1] = f[q] + 1;                     } else {                        g[q + 1] = f[q + 1];                    }                }                for (int q = 1; q < n; ++q) {                    g[q + 1] = max(g[q + 1], g[q]);                }                g[0] = 0;                int nmask = 0;                REP(q, n) if (g[q + 1] > g[q]) {                    nmask |= 1 << q;                }                t[mask][j] = nmask;    //            cout<<"// "<<mask<<" "<<j<<" "<<nmask<<endl;            }    //        cout<<"-----------"<<endl;        }        REP(times, n) {            memset(nd, 0, sizeof nd);            REP(mask, MX) if (d[mask]) {                REP(j, k) {                    int nmask = t[mask][j];                    modAdd(nd[nmask], d[mask]);                }            }            memcpy(d, nd, sizeof d);        }        int ans = 0;        REP(mask, MX) if (bc[mask] == l) {            modAdd(ans, d[mask]);        }        printf("%d\n", ans);    }    return 0;}                  


0 0
原创粉丝点击