題目鏈結:洛谷點我:-)
uoj點我:-)
題目描述:
如果乙個字串可以被拆分為 aabb 的形式,其中 a和 b是任意非空字串,則我們稱該字串的這種拆分是優秀的。
例如,對於字串 aabaabaa,如果令 a=aab,b=a,我們就找到了這個字串拆分成 aabb的一種方式。
乙個字串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比如我們令 a=a,b=baa,也可以用 aabb表示出上述字串;但是,字串 abaabaa 就沒有優秀的拆分。
現在給出乙個長度為 n(n <= 30000)的字串 s,我們需要求出,在它所有子串的所有拆分方式中,優秀拆分的總個數。這裡的子串是指字串中連續的一段。
以下事項需要注意:
1.出現在不同位置的相同子串,我們認為是不同的子串,它們的優秀拆分均會被記入答案。
2.在乙個拆分中,允許出現 a=b。例如 cccc 存在拆分 a=b=c。
3.字串本身也是它的乙個子串。
輸入格式:
每個輸入檔案包含多組資料。輸入檔案的第一行只有乙個整數 t,表示資料的組數。保證 1≤t≤10。
接下來 t行,每行包含乙個僅由英文小寫字母構成的字串 s,意義如題所述。
輸出格式:
輸出 t行,每行包含乙個整數,表示字串 s 所有子串的所有拆分中,總共有多少個是優秀的拆分。
思路:
求兩個陣列:st[i]與en[i],分別表示以i這個字元開頭與以i這個字元結尾的『aa』形式的串有多少個,那麼答案就是∑n
−1i=
1st[
i+1]
∗en[
i],難點在於如何求出這兩個陣列:
我們列舉乙個長度
l表示當前找的『aa』型串的長度的一半,列舉i=
k∗l,
j=i+
l, 記x
=lcp
(suf
(i),
suf(
j)), 記y=
lcs(
pre(
i−1)
,pre
(j−1
)), 如果x+
y>=l,記
t=x+
y−l+
1,表示我們找到了t個長度為2l
的』aa『串
(自己可以舉個例子看看,如』abcabcab『)
為了方便理解,假設x+
y=l,那麼我們恰好找到乙個(i
−y,j
+x−1
)的』aa『串。
但是每次有乙個連續區間,我們不能乙個乙個加上,因為時效會出問題。所以用到差分的思想(當然有閒心寫線段樹也是可以的),在區間開始的地方加一,在區間結束的後乙個位置減一,那麼最後做一遍字首和即可。
注意:每次要清c1, c2(即x, y)陣列,因為後面的「y[sa[i]+k]==y[sa[i-1]+k]」可能會越限
感想:
這題最開始用kmp寫了個95分暴力,覺得可以了,就沒做了。然後某一天發現小夥伴都寫了滿分啊,嚇得我趕緊寫
真心想不出正解,然而網上的題解又很敷衍,幸虧有dy大神的幫助,不然我就做不出來了qwq。有點難理解,其實也還好啦。但是。。。正解是怎麼想到的qwq
畢竟**不難寫,所以妙妙以後要多練思維(-_-|||)
想想,覺得本題也可以用hash解決,找個時間寫寫把**再貼上來吧。。。
**:
95分大暴力
//miaomiao 2016.8.2
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define maxs (2000+5)
int f[maxs][maxs];
vector
xh[maxs];
void init()
void get_fail(int now, char *s)
}char s[maxs];
int main()
}int ans = 0;
for(int i = 0; i < slen; i++)
}printf("%d\n", ans);
}return
0;}
看了題解的正解
//miaomiao 2017.1.28
#include
#include
#include
#include
#include
using
namespace
std;
#define ll long long
#define set(a, v) memset(a, v, sizeof(a))
#define for(i, a, b) for(int i = (a); i <= (int)(b); i++)
#define forr(i, a, b) for(int i = (a); i >= (int)(b); i--)
#define log (15+5)
#define maxn (30000+5)
int n, c[maxn], c1[maxn], c2[maxn], log[maxn];
struct suffixarray
void buildsa(int m='z')
}void getheight()
for(j, 1, 15) for(i, 1, n)
}int lcp(int x, int y)}}
for(i, 1, n) st[i]+=st[i-1], en[i]+=en[i-1];
ll ans = 0;
for(i, 1, n) ans += 1ll*en[i]*st[i+1];
printf("%lld\n", ans);
}return
0;}
NOI2016優秀的拆分 字尾陣列
題目描述 如果乙個字串可以被拆分為 aabb 的形式,其中 a和 b是任意非空字串,則我們稱該字串的這種拆分是優秀的。例如,對於字串 aabaabaa,如果令 a aab,b a,我們就找到了這個字串拆分成 aabb的一種方式。乙個字串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比如我們令 a...
字尾陣列 NOI2016 優秀的拆分
如果乙個字串可以被拆分為 aa bb的形式,其中 a 和 b 是任意非空字串,則我們稱該字串的這種拆分是優秀的。例如,對於字串 aabaabaa,如果令 a aab,b a,我們就找到了這個字串拆分成 aa bb的一種方式。乙個字串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比如我們令 a a...
NOI2016 優秀的拆分(字尾陣列)
如果乙個字串可以被拆分為aabbaabb的形式,其中 a和 b是任意非空字串,則我們稱該字串的這種拆分是優秀的。例如,對於字串aabaabaa,如果令 a aab,b a,我們就找到了這個字串拆分成 aabb的一種方式。乙個字串可能沒有優秀的拆分,也可能存在不止一種優秀的拆分。比如我們令 a a,b...