【链接】h在这里写链接

【题意】

    【Description】
        给你n(n<=10^9)个数字,把它们依次,一个一个地添加在空串S的后面.
        要求每添加一次之后,都要求出串S的本质不同的子串个数。
        即维护字符串的本质不同的子串个数.

【题解】

    把整个字符串倒过来。
    这样,就变成求从第n-i开始的后缀,它本质不同的子串的个数了。
    我们可以利用前i-1个的答案,对于第i个答案;看看从第n-i开始的后缀会和之前哪些已经算过的
    后缀产生重叠的部分->lcp->则减去lcp就是新增加的子串的个数了。
    (这部分lcp是什么时候算的不重要,反正你只要知道它之前有被算过就好了);
    ->回忆一下求n个字符的不同子串的时候的做法,则我们只要找到已经算过的,和它排名相邻(最靠近)的两个后缀.
    答案+=n-i-max(lcp1,lcp2);
    cout << 答案 << endl;
        n个字符不同子串的时候,只要删掉height[i]就可以了,是因为Rank为i+1的后缀我们还没算,
        (因为我们是顺序i从1..n的)..所以不用考虑Height[i+1])

【错的次数】

0

【反思】

Tip:前缀问题,倒转一下就能转化为后缀问题了.

【代码】

#include<bits/stdc++.h>
#define ll long long
using namespace std;const int N = 2e5;
const int MAX_CHAR = 1e5+10;//每个数字的最大值。
int s[N + 10];//如果是数字,就写成int s[N+10]就好,从0开始存
int Sa[N + 10], T1[N + 10], T2[N + 10], C[N + 10];
int Height[N + 10], Rank[N + 10];
map <int, int> dic;void build_Sa(int n, int m) {int i, *x = T1, *y = T2;for (i = 0; i<m; i++) C[i] = 0;for (i = 0; i<n; i++) C[x[i] = s[i]]++;for (i = 1; i<m; i++) C[i] += C[i - 1];for (i = n - 1; i >= 0; i--) Sa[--C[x[i]]] = i;for (int k = 1; k <= n; k <<= 1){int p = 0;for (i = n - k; i<n; i++) y[p++] = i;for (i = 0; i<n; i++) if (Sa[i] >= k) y[p++] = Sa[i] - k;for (i = 0; i<m; i++) C[i] = 0;for (i = 0; i<n; i++) C[x[y[i]]]++;for (i = 1; i<m; i++) C[i] += C[i - 1];for (i = n - 1; i >= 0; i--) Sa[--C[x[y[i]]]] = y[i];swap(x, y);p = 1; x[Sa[0]] = 0;for (i = 1; i<n; i++)x[Sa[i]] = y[Sa[i - 1]] == y[Sa[i]] && y[Sa[i - 1] + k] == y[Sa[i] + k] ? p - 1 : p++;if (p >= n) break;m = p;}
}void getHeight(int n)
{int i, j, k = 0;for (i = 1; i <= n; i++) Rank[Sa[i]] = i;for (i = 0; i<n; i++) {if (k) k--;j = Sa[Rank[i] - 1];while (s[i + k] == s[j + k]) k++;Height[Rank[i]] = k;}
}const int MAXL = 18;//log2数组的最大长度
const int INF = 0x3f3f3f3f;//数值绝对值的最大值
int n, tot;
set <int> mset;struct abc {int pre2[MAXL + 5], need[N + 10];int fmax[N + 10][MAXL + 5], fmin[N + 10][MAXL + 5];void init(int n){pre2[0] = 1;for (int i = 1; i <= MAXL; i++){pre2[i] = pre2[i - 1] << 1;}need[1] = 0; need[2] = 1;int temp = 2;for (int i = 3; i <= n; i++)//need[i]表示长度为i是2的多少次方,可以理解为[log2i]if (pre2[temp] == i)need[i] = need[i - 1] + 1, temp++;elseneed[i] = need[i - 1];}void getst(int *a, int n){memset(fmax, -INF, sizeof fmax);memset(fmin, INF, sizeof fmin);for (int i = 1; i <= n; i++)//下标从0开始就改成对应的就好fmax[i][0] = fmin[i][0] = a[i];for (int l = 1; pre2[l] <= n; l++)for (int i = 1; i <= n; i++)if (i + pre2[l] - 1 <= n)fmax[i][l] = max(fmax[i][l - 1], fmax[i + pre2[l - 1]][l - 1]);for (int l = 1; pre2[l] <= n; l++)for (int i = 1; i <= n; i++)if (i + pre2[l] - 1 <= n)fmin[i][l] = min(fmin[i][l - 1], fmin[i + pre2[l - 1]][l - 1]);}int getmin(int l, int r){int len = need[r - l + 1];return min(fmin[l][len], fmin[r - pre2[len] + 1][len]);}int getmax(int l, int r){int len = need[r - l + 1];return max(fmax[l][len], fmax[r - pre2[len] + 1][len]);}}ST;int main() {//freopen("F:\\rush.txt", "r", stdin);scanf("%d", &n);for (int i = 0; i <= n-1; i++) {int x;scanf("%d", &x);if (dic[x] == 0) dic[x] = ++tot;s[n-i-1] = dic[x];}s[n] = 0;build_Sa(n + 1, MAX_CHAR);//注意调用n+1getHeight(n);ST.init(n);ST.getst(Height, n);ll ans = 1;mset.insert(Rank[n - 1]);printf("%lld\n", ans);for (int i = n - 2; i >= 0; i--){int mx = 0;set<int>::iterator it = mset.upper_bound(Rank[i]);if (it != mset.end()) mx = max(mx, ST.getmin(Rank[i] + 1, *it));if (it != mset.begin()){it--;mx = max(mx, ST.getmin((*it) + 1, Rank[i]));}ans += n - i - mx;mset.insert(Rank[i]);printf("%lld\n", ans);}return 0;
}

转载于:https://www.cnblogs.com/AWCXV/p/7625981.html

【BZOJ 4516】生成魔咒相关推荐

  1. BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]

    4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...

  2. 【刷题】BZOJ 4516 [Sdoi2016]生成魔咒

    Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例 ...

  3. [SDOI2016]生成魔咒

    4516: [Sdoi2016]生成魔咒 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1460  Solved: 835 [Submit][Sta ...

  4. BZOJ4516: [Sdoi2016]生成魔咒

    BZOJ4516: [Sdoi2016]生成魔咒 Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示. 例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒 ...

  5. P4070 [SDOI2016]生成魔咒

    P4070 [SDOI2016]生成魔咒 题意: 有n个字符xi,每次在S的末尾加入一个字符,(一开始S为空),每次加入xi后的不相同字串有多少个 题解: 做这个题首先要会后缀数组P3809 [模板] ...

  6. [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数

    problem luogu-P4070 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]. 一个魔咒串 ...

  7. 【ACWing】2572. 生成魔咒

    题目地址: https://www.acwing.com/problem/content/2574/ 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1 , 2 1, 2 1,2 ...

  8. 【SDOI2016】生成魔咒

    Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例 ...

  9. 洛谷 P4070 [SDOI2016]生成魔咒 解题报告

    P4070 [SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 \(1\).\(2\) 拼凑起来形成一个魔咒串 \([1,2]\). 一个魔咒 ...

  10. P4070 [SDOI2016]生成魔咒(SAM len数组的含义)

    [SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1 , 2 1,2 1,2 拼凑起来形成一个魔咒串 [ 1 , 2 ] [1,2] [1, ...

最新文章

  1. ATS 4.2.3隐藏服务器名称及版本号的方法
  2. Python常用函数--文档字符串DocStrings
  3. matlab数组元素对应相减,MATLAB下矩阵的运算 看完你就知道了
  4. js 验证身份证号码
  5. android 横屏finish 会变竖屏,[android] Activity 的生命周期 以及 横屏竖屏切换时 Activity 的状态变化...
  6. DAppDiscover | 盘点2018年度十大DAPP
  7. hibernate+spring+struts集成,并自动生成实体类和DAO层的步奏
  8. nvm nodejs npm快速安装
  9. WIN7 MBR转GPT分区实现UEFI启动
  10. 2022-2027年(新版)中国条码识读设备行业运行形势与发展策略建议报告
  11. 网络服务——数据链路层--三层交换机接口模式-access和trunk命令详解
  12. 国外量化投资经典案例介绍
  13. 计算机无线网络计算机文件共享,两台电脑怎么用无线网络共享文件?
  14. 关于rand()和srand()
  15. volatility取证
  16. [No0000C7]windows 10桌面切换快捷键,win10
  17. 如何处理高并发和单点故障
  18. 解决ubuntu下外接2k显示器却无法调2k分辨率问题
  19. C#区域性语言(CultureInfo)与资源本地化(WINFORM,多线程,原理可适用于网络开发)
  20. DCS概念简述——以教学用ABB HT 600控制系统/WinCS为例

热门文章

  1. Salesforce Ventures为云初创公司Vlocity注资5000万美元
  2. 一个比较好的多人网络游戏菜单程序。
  3. 取出Cookie中的中文显示乱码解决方法。经验证第三种方法有效。
  4. LINUX邮件服务器
  5. 跨浏览器resize事件分析
  6. C++通过WIN32 API获取逻辑磁盘详细信息
  7. Wcf使用Net.Tcp做回调操作
  8. 写在2012的最后一天
  9. [转]android MapView 定位与Overlay onTap事件处理
  10. 一个Repeater的分页方法