【BZOJ 4516】生成魔咒
【链接】h在这里写链接
【题意】
给你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])
【错的次数】
【反思】
【代码】
#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】生成魔咒相关推荐
- BZOJ 4516: [Sdoi2016]生成魔咒 [后缀自动机]
4516: [Sdoi2016]生成魔咒 题意:询问一个字符串每个前缀有多少不同的子串 做了一下SDOI2016R1D2,题好水啊随便AK 强行开map上SAM 每个状态的贡献就是\(Max(s)-M ...
- 【刷题】BZOJ 4516 [Sdoi2016]生成魔咒
Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例 ...
- [SDOI2016]生成魔咒
4516: [Sdoi2016]生成魔咒 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1460 Solved: 835 [Submit][Sta ...
- BZOJ4516: [Sdoi2016]生成魔咒
BZOJ4516: [Sdoi2016]生成魔咒 Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示. 例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒 ...
- P4070 [SDOI2016]生成魔咒
P4070 [SDOI2016]生成魔咒 题意: 有n个字符xi,每次在S的末尾加入一个字符,(一开始S为空),每次加入xi后的不相同字串有多少个 题解: 做这个题首先要会后缀数组P3809 [模板] ...
- [SDOI2016] 生成魔咒(后缀数组SA + st表 + set)动态不同子串个数
problem luogu-P4070 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1,21,21,2 拼凑起来形成一个魔咒串 [1,2][1,2][1,2]. 一个魔咒串 ...
- 【ACWing】2572. 生成魔咒
题目地址: https://www.acwing.com/problem/content/2574/ 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1 , 2 1, 2 1,2 ...
- 【SDOI2016】生成魔咒
Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例 ...
- 洛谷 P4070 [SDOI2016]生成魔咒 解题报告
P4070 [SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 \(1\).\(2\) 拼凑起来形成一个魔咒串 \([1,2]\). 一个魔咒 ...
- P4070 [SDOI2016]生成魔咒(SAM len数组的含义)
[SDOI2016]生成魔咒 题目描述 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1 , 2 1,2 1,2 拼凑起来形成一个魔咒串 [ 1 , 2 ] [1,2] [1, ...
最新文章
- ATS 4.2.3隐藏服务器名称及版本号的方法
- Python常用函数--文档字符串DocStrings
- matlab数组元素对应相减,MATLAB下矩阵的运算 看完你就知道了
- js 验证身份证号码
- android 横屏finish 会变竖屏,[android] Activity 的生命周期 以及 横屏竖屏切换时 Activity 的状态变化...
- DAppDiscover | 盘点2018年度十大DAPP
- hibernate+spring+struts集成,并自动生成实体类和DAO层的步奏
- nvm nodejs npm快速安装
- WIN7 MBR转GPT分区实现UEFI启动
- 2022-2027年(新版)中国条码识读设备行业运行形势与发展策略建议报告
- 网络服务——数据链路层--三层交换机接口模式-access和trunk命令详解
- 国外量化投资经典案例介绍
- 计算机无线网络计算机文件共享,两台电脑怎么用无线网络共享文件?
- 关于rand()和srand()
- volatility取证
- [No0000C7]windows 10桌面切换快捷键,win10
- 如何处理高并发和单点故障
- 解决ubuntu下外接2k显示器却无法调2k分辨率问题
- C#区域性语言(CultureInfo)与资源本地化(WINFORM,多线程,原理可适用于网络开发)
- DCS概念简述——以教学用ABB HT 600控制系统/WinCS为例