P4248 [AHOI2013]差异
生活随笔
收集整理的這篇文章主要介紹了
P4248 [AHOI2013]差异
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
P4248 [AHOI2013]差異
題意:
∑1≤i<j≤nlen(Ti)+len(Tj)?2?lcp(Ti,Tj)\sum_{1\leq i<j\leq n}len(T_{i})+len(T_{j})-2*lcp(T_{i},T_{j})∑1≤i<j≤n?len(Ti?)+len(Tj?)?2?lcp(Ti?,Tj?)
題解:
∑1≤i<j≤nlen(Ti)+len(Tj)\sum_{1\leq i<j\leq n}len(T_{i})+len(T_{j})∑1≤i<j≤n?len(Ti?)+len(Tj?)這部分好說,就是n * (n - 1) * (n + 1) / 2
對于lcp(Ti,Tj),就是min(Height[l+1]…Height[r] ),l = 后綴suf(i)的排名,r = 后綴suf(j)的排名
那我們就要計算所有區間的權值和,每個區間的權值為該區間的最小值。
那我們可以考慮對于每個height[i],他給多少區間做了貢獻,可以用單調棧
這個區間貢獻計算方式:
如果第i個數是l到r中最小的
貢獻就是:(i-l+1)*(r-i+1)
處理出l和r,用單調棧
注意:l表示小于i的第一個,r表示小于等于i的第一個
左開右閉
這里卡了我一個多小時。。
代碼:
// Problem: P4248 [AHOI2013]差異 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P4248 // Memory Limit: 500 MB // Time Limit: 2000 ms // Data:2021-08-22 15:25:53 // 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= 1000005;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);//這個知道原理后就比較好理解程序 }void Init() {scanf("%s", str);n= strlen(str);for (int i= 0; i < n; i++)a[i + 1]= str[i]; } int st[MAXN], l[MAXN]; int main() {//rd_test();Init();Suffix();int tail= 0;ll sum= 1ll * n * (n - 1) * (n + 1) / 2;height[0]= height[n + 1]= 0;//st[tail= 1]= 0;=st[0]= 1;for (int i= 1; i <= n; i++) {while (tail && height[st[tail]] >= height[i])tail--;int pos= st[tail];l[i]= (i - pos);st[++tail]= i;}tail= 0;st[0]= n + 1;for (int i= n; i >= 1; i--) {while (tail && height[st[tail]] > height[i])tail--;int pos= st[tail];sum-= (2ll * l[i] * (pos - i)) * height[i];st[++tail]= i;}cout << sum;//Time_test(); } /* ll sum= 1ll * n * (n - 1) * (n + 1) / 2;height[0]= height[n + 1]= 0;//st[tail= 1]= 0;for (int i= 1; i <= n; i++) {while (tail && height[st[tail]] > height[i])tail--;int pos= st[tail];f[i]= f[pos] + 1ll * (i - pos) * height[i];// sum-= 2ll * (i - pos) * height[i];sum-= 2 * f[i];st[++tail]= i;} */總結
以上是生活随笔為你收集整理的P4248 [AHOI2013]差异的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 胃难受吃什么药好
- 下一篇: Display Substring