求本质不同的子序列数目

法一

dpi 表示以 i 为结尾的答案,记录 lasi 表示 i 上一次出现的位置。

dpi=j=lasaii1dpj,可以前缀和优化。

最后答案为 sumn1,因为这里的答案包含空串,要减去。

点击查看代码
// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
// 没有力量的理想是戏言,没有理想的力量是空虚
#include <bits/stdc++.h>
#define LL long long
using namespace std;
char ibuf[1 << 15], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 15, stdin), p1==p2) ? EOF : *p1++)
inline int read() {
  char ch = getchar();  int x = 0, f = 1;
  while (ch < '0' || ch > '9')  {  if (ch == '-')  f = -1;  ch = getchar();  }
  while (ch >= '0' && ch <= '9')  x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
  return x * f;
}
void print(LL x) {
  if (x > 9)  print(x / 10);
  putchar(x % 10 + '0');
}
template<class T> bool chkmin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool chkmax(T &a, T b) { return a < b ? (a = b, true) : false; }
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define repd(i, l, r) for (int i = (l); i >= (r); i--)
#define REP(i, l, r)  for (int i = (l); i < (r); i++)
const int N = 2e6, mod = 1e9 + 7;
int n, a[N], dp[N], sum[N], las[N];
void solve() {
  n = read();
  rep (i, 1, n)  a[i] = read();
  sum[0] = 1;
  rep (i, 1, n) {
    if (las[ a[i] ] == 0)  dp[i] = sum[i - 1];
    else  dp[i] = sum[i - 1], dp[i] -= sum[ las[ a[i] ] - 1 ], dp[i] %= mod;
    sum[i] = sum[i - 1] + dp[i];  sum[i] %= mod;
    las[ a[i] ] = i;
  } 
  int ans = sum[n] - 1;  ans %= mod;  ans += mod;  ans %= mod;
  cout << ans << "\n";  return;
}
signed main () {
#ifdef LOCAL_DEFINE
  freopen("1.in", "r", stdin);
  freopen("1.ans", "w", stdout);
#endif
  int T = 1;  while (T--)  solve();
#ifdef LOCAL_DEFINE
  cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
  return 0;
}

法二

dpi 表示以 i 为结尾的答案,记录 lasi 表示 i 上一次出现的位置。

如果当前 ai 还没有出现过,那么 dpi=2×dpi1+1

表示前面的 dpi1 中是否加入一个 ai,以及只选 ai 的情况 (+1)。

如果当前 ai 已经出现过了,其中对于 [1,lasai1] 中的状态将会重复计算,那么需要减去这部分的答案,于是 dpi=2×dpi1dplasai1

点击查看代码
// 德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱德丽莎你好可爱
// 德丽莎的可爱在于德丽莎很可爱,德丽莎为什么很可爱呢,这是因为德丽莎很可爱!
// 没有力量的理想是戏言,没有理想的力量是空虚
#include <bits/stdc++.h>
#define LL long long
using namespace std;
char ibuf[1 << 15], *p1, *p2;
#define getchar() (p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 1 << 15, stdin), p1==p2) ? EOF : *p1++)
inline int read() {
  char ch = getchar();  int x = 0, f = 1;
  while (ch < '0' || ch > '9')  {  if (ch == '-')  f = -1;  ch = getchar();  }
  while (ch >= '0' && ch <= '9')  x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
  return x * f;
}
void print(LL x) {
  if (x > 9)  print(x / 10);
  putchar(x % 10 + '0');
}
template<class T> bool chkmin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool chkmax(T &a, T b) { return a < b ? (a = b, true) : false; }
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define repd(i, l, r) for (int i = (l); i >= (r); i--)
#define REP(i, l, r)  for (int i = (l); i < (r); i++)
const int N = 2e6, mod = 1e9 + 7;
int n, a[N], dp[N], las[N];
void solve() {
  n = read();
  rep (i, 1, n)  a[i] = read();
  dp[1] = 1;  las[ a[1] ] = 1;
  rep (i, 2, n) {
    if (las[ a[i] ] == 0)  dp[i] = dp[i - 1] * 2 + 1, dp[i] %= mod;
    else {
      dp[i] = dp[i - 1] * 2 - dp[ las[ a[i] ] - 1 ];
      dp[i] %= mod;  dp[i] += mod;  dp[i] %= mod;
    }
    las[ a[i] ] = i;
  }
  dp[n] %= mod;  dp[n] += mod;  dp[n] %= mod;
  cout << dp[n] << "\n";
}
signed main () {
#ifdef LOCAL_DEFINE
  freopen("1.in", "r", stdin);
  freopen("1.ans", "w", stdout);
#endif
  int T = 1;  while (T--)  solve();
#ifdef LOCAL_DEFINE
  cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
  return 0;
}

法三

fi,j 表示前 i 个字符,选 j 的答案。

fi,j={fi1,j,sijkfi1,k+1,si=j

可以矩阵优化,对角线染 1,然后对应列染 1 即可。

法四

fi,j,k 表示前 i 个字符,以 j 结尾,长度为 k 的答案。

fi,j,k={fi1,j,k,sijtfi1,t,k1+[k=1],si=j

posted @   Pitiless0514  阅读(635)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示