Display Substring
生活随笔
收集整理的這篇文章主要介紹了
Display Substring
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Display Substring
題意:
一個長度為n的字符串,每個字符有自己的價值,求第k小價值的不重復子串價值
題解:
首先眾所周知,所有子串都可以用后綴的前綴來表示,這就和后綴數組扯上關系了
我們可以直接二分這個價值val,然后去算大于val的不重復子串有多少個(比如有x個),如果x大于k,說明該價值的情況下存在第k小價值,那r可以縮小,否則l可以增大,這是二分過程
那如果計算大于val的不重復子串有多少個,遍歷后綴數組,對于每個后綴,如果其越長說明其價值越高,符合單調性,所有我們二分(沒錯二分套二分),二分找到價值小于等于val的值的前綴有多少個,再減去重復部分,看是否大于k,如果大于第一個二分就返回true
重復部分就是height數組對應的值,通過這題可以知道P2408 不同子串個數
注意height要和后綴二分出來的距離取min,因為要刪除重復部分不能比這個字符串的長度還長
代碼:
// Problem: Display Substring // Contest: HDOJ // URL: https://acm.hdu.edu.cn/showproblem.php?pid=6988 // Memory Limit: 262 MB // Time Limit: 8000 ms // Data:2021-08-22 17:57:49 // By Jozky#include <bits/stdc++.h> #include <unordered_map> #define debug(a, b) printf("%s = %d\n", a, b); using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> PII; clock_t startTime, endTime; //Fe~Jozky const ll INF_ll= 1e18; const int INF_int= 0x3f3f3f3f; void read(){}; template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar) {x= 0;char c= getchar();bool flag= 0;while (c < '0' || c > '9')flag|= (c == '-'), c= getchar();while (c >= '0' && c <= '9')x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();if (flag)x= -x;read(Ar...); } template <typename T> inline void write(T x) {if (x < 0) {x= ~(x - 1);putchar('-');}if (x > 9)write(x / 10);putchar(x % 10 + '0'); } void rd_test() { #ifdef LOCALstartTime= clock();freopen("in.txt", "r", stdin); #endif } void Time_test() { #ifdef LOCALendTime= clock();printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC); #endif } const int MAXN= 3e5;char ch[MAXN], all[MAXN]; int sa[MAXN], rk[MAXN], height[MAXN], tax[MAXN], tp[MAXN], a[MAXN], n, m; char str[MAXN]; //rk[i] 第i個后綴的排名; sa[i] 排名為i的后綴位置; height[i] 排名為i的后綴與排名為(i-1)的后綴的LCP //tax[i] 計數排序輔助數組; tp[i] rk的輔助數組(計數排序中的第二關鍵字),與sa意義一樣。 //a為原串 void RSort() {//rk第一關鍵字,tp第二關鍵字。for (int i= 0; i <= m; i++)tax[i]= 0;for (int i= 1; i <= n; i++)tax[rk[tp[i]]]++;for (int i= 1; i <= m; i++)tax[i]+= tax[i - 1];for (int i= n; i >= 1; i--)sa[tax[rk[tp[i]]]--]= tp[i]; //確保滿足第一關鍵字的同時,再滿足第二關鍵字的要求 } //計數排序,把新的二元組排序。int cmp(int* f, int x, int y, int w) {return f[x] == f[y] && f[x + w] == f[y + w]; } //通過二元組兩個下標的比較,確定兩個子串是否相同void Suffix() {//safor (int i= 1; i <= n; i++)rk[i]= a[i], tp[i]= i;m= 127, RSort(); //一開始是以單個字符為單位,所以(m = 127)for (int w= 1, p= 1, i; p < n; w+= w, m= p) { //把子串長度翻倍,更新rk//w 當前一個子串的長度; m 當前離散后的排名種類數//當前的tp(第二關鍵字)可直接由上一次的sa的得到for (p= 0, i= n - w + 1; i <= n; i++)tp[++p]= i; //長度越界,第二關鍵字為0for (i= 1; i <= n; i++)if (sa[i] > w)tp[++p]= sa[i] - w;//更新sa值,并用tp暫時存下上一輪的rk(用于cmp比較)RSort(), swap(rk, tp), rk[sa[1]]= p= 1;//用已經完成的sa來更新與它互逆的rk,并離散rkfor (i= 2; i <= n; i++)rk[sa[i]]= cmp(tp, sa[i], sa[i - 1], w) ? p : ++p;}//離散:把相等的字符串的rk設為相同。//LCPint j, k= 0;for (int i= 1; i <= n; height[rk[i++]]= k)for (k= k ? k - 1 : k, j= sa[rk[i] - 1]; a[i + k] == a[j + k]; ++k);//這個知道原理后就比較好理解程序 } ll k; ll sum[MAXN]; ll val[MAXN]; inline void clear() {memset(tax, 0, sizeof(tax));memset(sa, 0, sizeof(int) * (n + 1));memset(height, 0, sizeof(int) * (n + 1));memset(rk, 0, sizeof(int) * (n + 1));memset(sum, 0, sizeof(int) * (n + 1));memset(tp, 0, sizeof(int) * (n + 1));memset(a, 0, sizeof(int) * (n + 1)); }void Init() {scanf("%d%lld", &n, &k);scanf("%s", str + 1);for (int i= 1; i <= n; i++)a[i]= str[i];// cout << (str + 1) << endl;for (int i= 1; i <= 26; i++)read(val[i]);for (int i= 1; i <= n; i++)sum[i]= sum[i - 1] + val[str[i] - 'a' + 1]; } bool check(int x) {ll ans= 0;for (int i= 1; i <= n; i++) {int l= sa[i], r= n;while (l < r) {int mid= (l + r + 1) >> 1;if (sum[mid] - sum[sa[i] - 1] <= x)l= mid;elser= mid - 1;}if (sum[l] - sum[sa[i] - 1] <= x) {ans+= l - sa[i] + 1;ans-= min(height[i], l - sa[i] + 1);}}return ans >= k; } int main() {//rd_test();int t;read(t);while (t--) {clear();Init();Suffix();int l= 1, r= 0;for (int i= 1; i <= n; i++)r+= val[str[i] - 'a' + 1];// cout << "r=" << r << endl;while (l < r) {int mid= (l + r) >> 1;if (check(mid))r= mid;elsel= mid + 1;}if (!check(l))l= -1;printf("%d\n", l);}//Time_test(); }總結
以上是生活随笔為你收集整理的Display Substring的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P4248 [AHOI2013]差异
- 下一篇: 闪到腰怎么办