1 条题解

  • 0
    @ 2025-8-24 22:44:52

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 喵仔牛奶
    黄昏再美终要黑夜。

    搬运于2025-08-24 22:44:52,当前版本为作者最后更新于2024-07-10 20:28:42,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    O(nΣ)\mathcal{O}(n\cdot\lvert\Sigma\rvert) 题解,可以加强到 Σ=26\lvert\Sigma\rvert=26 及以上。

    Solution

    Part I

    我们观察一个子串的合法条件,记 SS 为子串 [l,r][l,r] 中字符组成的集合,eie_iii 的出现次数,从 SS 中任选一个数 xx,可以得到条件为:

    iS,eiex=0\forall i\in S,e_i-e_x=0

    我们记 si,js_{i,j} 是前 ii 个位置中 jj 的出现次数,则上述条件变为:

    $$\forall i\in S,s_{r,i}-s_{l-1,i}-s_{r,x}+s_{l-1,x}=0 $$$$\forall i\in S,s_{r,i}-s_{r,x}=s_{l-1,i}-s_{l-1,x} $$

    也就是说,我们固定 S,xS,x,记 di,j=si,jsi,xd_{i,j}=s_{i,j}-s_{i,x},子串 [l,r][l,r] 的合法条件就是:

    $$\begin{cases} \forall i\in S,d_{r,i}=d_{l-1,i},\\ \forall i\notin S,s_{r,i}=s_{l-1,i} \end{cases} $$

    Part II

    我们要枚举的是 SS,当然不能大力 2Σ2^{\lvert\Sigma\rvert} 枚举。我们有结论:

    • 固定左端点 ll,所有右端点 rr 产生 SS 的种类只有 Σ\lvert\Sigma\rvert 种。固定右端点同理。

    我们考虑向右拓展,一种字符之后被加入一次。我们记 LiL_i 是右端点为 ii 向左拓展过程中所有 SS 的集合,RiR_i 是左端点为 ii 向右拓展过程中所有 SS 的集合。

    我们同时枚举端点与集合。枚举左端点与集合 (l,S)(l,S)SRlS\in R_l)、右端点与集合 (r,T)(r,T)TLrT\in L_r)。为了方便,我们将 xx 取集合中最小值,即 x=minS,x=minTx=\min S,x'=\min T。将 d,sd,s 统一,记 $p_{i,j}=s_{i,j}-\begin{cases}s_{i,x}&j\in S\\0&j\notin S\end{cases}$,$q_{i,j}=s_{i,j}-\begin{cases}s_{i,x'}&j\in T\\0&j\notin T\end{cases}$。可以得出 [l,r][l,r] 合法的条件是:

    $$\begin{cases} l\leq r,\\ S=T,\\ p_{l-1}=q_r \end{cases} $$

    大力枚举是 O(n2Σ2)\mathcal{O}(n^2\cdot\lvert\Sigma\rvert^2) 的,我们发现三个条件除了第一个都是相等,自然分别枚举 (l,S),(r,T)(l,S),(r,T) 放进哈希表计数。

    考虑到 lrl\leq r,我们枚举 i=0,1,2,,ni=0,1,2,\cdots,n,先统计以 ii 为右端点的答案,即枚举 SLiS\in L_i,算出 pp,答案加上哈希表里 (S,p)(S,p) 的个数;再枚举 TRi1T\in R_{i-1},算出 qq,将 (T,q)(T,q) 放入哈希表。

    枚举的时候每次往 S,TS,T 里加入一个字符,所以 p,qp,q 与哈希值也是可以维护的。时间复杂度 O(nΣ)\mathcal{O}(n\cdot\lvert\Sigma\rvert)

    细节见代码,有注释。

    Code

    #include <bits/stdc++.h>
    #define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
    #define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
    #define fi first
    #define se second
    #define pb emplace_back
    #define mems(x, v) memset((x), (v), sizeof(x))
    using namespace std;
    namespace Milkcat {
    	typedef long long LL;
    	typedef unsigned long long ULL;
    	typedef pair<LL, LL> pii;
    	const int N = 1e6 + 5, B = 1e7 + 7;
    	
    	LL n, m, rs, a[N], ct[N][26]; string st;
    	ULL pw[N]; vector<int> L[N], R[N];
    	unordered_map<ULL, int> S;
    	
    	void ins(vector<int>& s, int x) {
    		int t = -1;
    		for (int i = 0; i < s.size(); i ++)
    			if (s[i] == x) t = i;
    		if (t != -1) s.erase(s.begin() + t);
    		s.insert(s.begin(), x);
    	} // s 中没有 x 则将 x 加到最前,有则将里面 x 的位置放到最前。
    	
    	int main() {
    		cin >> st, n = st.size();
    		REP(i, 1, n) {
    			a[i] = st[i - 1] - 'a', m = max(m, a[i] + 1);
    			REP(j, 0, 25) ct[i][j] = ct[i - 1][j] + (a[i] == j); // ct 是题解中的 s
    		}
    		REP(i, 1, n) L[i] = L[i - 1], ins(L[i], a[i]);
    		DEP(i, n, 1) R[i] = R[i + 1], ins(R[i], a[i]);
    		// 处理出 L,R
    		pw[0] = 1;
    		REP(i, 1, n + m) pw[i] = pw[i - 1] * B;
    		
    		REP(i, 0, n) {
    			if (i > 0) {
    				ULL v = 0, w = 0, s = 0, c = 1e9; // v 是 p 的哈希值,w 是 S 的哈希值,s 辅助求哈希值,c 是 x(最小值)
    				DEP(j, m - 1, 0) v = v * B + ct[i][j];
    				for (int x : L[i]) {
    					if (x < c) v += s * (c < m ? ct[i][c] - ct[i][x] : 0), c = x;  // 最小值改变,要改变之前 -ct[i][c] 的部分(即 s)
    					v -= ct[i][c] * pw[x], s += pw[x], w |= 1 << x; // 加入一个数
    					rs += S[v + w * pw[m]]; // 统计答案
    				}
    			}
    			ULL v = 0, w = 0, s = 0, c = 1e9;
    			DEP(j, m - 1, 0) v = v * B + ct[i][j];
    			for (int x : R[i + 1]) {
    				if (x < c) v += s * (c < m ? ct[i][c] - ct[i][x] : 0), c = x;
    				v -= ct[i][c] * pw[x], s += pw[x], w |= 1 << x; // 和前面一模一样
    				S[v + w * pw[m]] ++;
    			}
    		}
    		cout << rs << '\n';
    		return 0;
    	}
    }
    int main() {
    //	freopen("c.in", "r", stdin);
    //	freopen("c.out", "w", stdout);
    	ios::sync_with_stdio(0);
    	cin.tie(0), cout.tie(0);
    	int T = 1;
    	while (T --) Milkcat::main();
    	return 0;
    }
    
    • 1

    信息

    ID
    8007
    时间
    3000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者