• 题解-CF1483F Exam[*medium]


    题面

    CF1483F. Exam

    给定 (n) 个不同的字符串 (S_1, S_2, ... S_n),求数对 ((i, j)) 的个数,满足 (S_i)(S_j) 的子串,且不存在一个不等于 (i)(j)(k) ,满足 (S_i)(S_k) 的子串且 (S_k)(S_j) 的子串。

    数据范围:(n, sum |S| le 10^6)

    题解

    我还是学傻了啊,经过神 sjy 的提醒才发现在这儿 ( m ACAM)( m SAM) 是等价的。


    考虑枚举长的字符串,短的字符串必然在长的字符串中出现。

    枚举短串的右端点,对答案有贡献的字符串一定是左端点最靠左边的。

    然后还要求没有其他的字符串包含这个字符串,可以简单地判掉。

    可以结合这张图理解

    qwqwq.png

    但是这样会算重,如何解决?

    发现只有 算到的次数 = 在长串中出现的次数 的情况对答案有 (1) 的贡献。

    算到的次数可以轻松维护,在长串中出现的次数可以用 树状数组 + ACAM 来维护。时间复杂度和空间复杂度都是 (Theta((sum|S|) log (sum|S|)))

    代码

    具体细节见代码

    #include<bits/stdc++.h>
    #define L(i, j, k) for(int i = j, i##E = k; i <= i##E; i++)
    #define R(i, j, k) for(int i = j, i##E = k; i >= i##E; i--)
    #define ll long long
    #define pii pair<int, int>
    #define x first
    #define y second
    #define sz(a) ((int) (a).size())
    using namespace std;
    const int N = 1e6 + 7;
    template<typename T> inline void cmax(T &x, T y) { if(x < y) x = y; }
    template<typename T> inline void cmin(T &x, T y) { if(y < x) x = y; }
    using namespace std;
    int ns, cnt[N], tot, fa[N];
    vector< int > change[N], e[N], qet[N];
    int ch[N][26], sz[N];
    void ad(int x, int y) { 
    	for(; x <= tot + 1; x += (x & -x)) sz[x] += y;
    }
    int query(int x) {
    	int res = 0;
    	for(; x; x -= (x & -x)) res += sz[x];
    	return res;
    }
    int qry(int l, int r) {
    	return query(r) - query(l - 1); 
    }
    int n, m, siz[N], hv[N], St[N], En[N], idtot, mx[N], sx[N], lef[N], sG[N];
    void dfs(int x) {
    	St[x] = ++idtot;
    	for(int v : e[x]) {
    		if(!sx[v]) sx[v] = sx[x];
    		mx[v] = max(mx[v], mx[x]), dfs(v);
    	}
    	En[x] = idtot;
    }
    void ins(string s) {
    	int now = 0;
    	L(i, 0, sz(s) - 1) {
    		if(!ch[now][s[i] - 'a']) ch[now][s[i] - 'a'] = ++tot;
    		now = ch[now][s[i] - 'a'];
    	}
    }
    void build() {
    	queue<int> q;
    	L(i, 0, 25) if(ch[0][i]) q.push(ch[0][i]);
    	while(!q.empty()) {
    		int u = q.front();
    		q.pop();
    		L(i, 0, 25) 
    			if(ch[u][i]) fa[ch[u][i]] = ch[fa[u]][i], q.push(ch[u][i]);
    			else ch[u][i] = ch[fa[u]][i];
    	}
    }
    string s[N];
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(0); cout.tie(0);
    	cin >> n;
    	L(i, 1, n) cin >> s[i], ins(s[i]);
    	L(i, 1, n) {
    		int now = 0;
    		L(j, 0, sz(s[i]) - 1) now = ch[now][s[i][j] - 'a'], change[now].push_back(i);
    		cmax(mx[now], sz(s[i])), sx[now] = now;
    	} 
    	build();
    	L(i, 1, tot) e[fa[i]].push_back(i);
    	dfs(0);
    	L(i, 1, n) {
    		L(j, 1, sz(s[i])) qet[j].clear();
    		int now = 0;
    		L(j, 0, sz(s[i]) - 1) {
    			now = ch[now][s[i][j] - 'a'], ad(St[now], 1);
    			if(j == sz(s[i]) - 1) now = fa[now];
    			lef[j] = j - mx[now] + 1, sG[j] = sx[now];
    		}
    		lef[sz(s[i])] = 1e9;
    		R(j, sz(s[i]) - 1, 0) {
    			if(lef[j] <= j && lef[j] < lef[j + 1]) qet[j - lef[j] + 1].push_back(sG[j]);
    			lef[j] = min(lef[j], lef[j + 1]);
    		}
    		L(j, 1, sz(s[i])) {
    			for(int x : qet[j]) cnt[x] ++;
    			for(int x : qet[j]) if(cnt[x]) ns += (qry(St[x], En[x]) == cnt[x]), 
    			cnt[x] = 0;
    		}
    		now = 0;
    		L(j, 0, sz(s[i]) - 1) now = ch[now][s[i][j] - 'a'], ad(St[now], -1);
    	}
    	cout << ns << "
    ";
    	return 0;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    语言模型工具kenlm安装
    linux操作系统远程连接方法
    Windows操作系统远程连接方法
    Majority Number III
    Majority Number II
    不同颜色在Halcon中的色相值规律
    流程图
    Redis实战(24)使用rdbtools工具来解析redis rdb文件
    EasyExcel
    pktgen 使用小记
  • 原文地址:https://www.cnblogs.com/zkyJuruo/p/14567932.html
Copyright © 2020-2023  润新知