• @codefoces



    @description@

    给定两个长度为 n 的字符串 a, b 与一个长度为 m 的字符串 s。

    问存在多少对区间 [l1, r1], [l2, r2](1 <= l1 <= r1 <= n, 1 <= l2 <= r2 <= n),使得:

    1)两个区间含有交集。即存在 x 满足 l1 <= x <= r1 且 l2 <= x <= r2。
    2)a[l1...r1] + b[l2...r2] = s。

    原题传送门。

    @solution@

    区间要有交集,可以等价认为是 l1 <= r2 且 l2 <= r1。

    由题,区间长度和 (r1 - l1 + 1) + (r2 - l2 + 1) = m。
    变形一下得到 (r2 - l1 + 1) + (r1 - l2 + 1) = m。
    结合上面要有交集的不等式,可以得到 1 <= (r2 - l1 + 1) < m。

    我们使用 z-algorithm 求出 a 中每一个 l1 与 s 的最长公共前缀,求出 b 中每一个 r2 与 s 的最长公共后缀。

    接着,从后往前扫描 a 中的每一个 l1,维护 x[i] 表示如果 r1 - l1 + 1 = i 时对应了多少 r2。查询只需要区间求和即可。
    因为 1 <= (r2 - l1 + 1) < m,得到 r2 的取值范围实际上是个滑动的区间。每一个 r2 的贡献是一个区间加。

    因此直接用树状数组即可。

    @accepted code@

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    
    const int MAXN = 500000;
    const int MAXM = 2*MAXN;
    
    int z[MAXM + MAXN + 5];
    char str[MAXM + MAXN + 5];
    
    void getZ(int len) {
    	int pos = 0, mxl = -1;
    	for(int i=1;i<len;i++) {
    		z[i] = (mxl >= i ? min(mxl - i + 1, z[i - pos]) : 0);
    		while( str[z[i]] == str[i+z[i]] ) z[i]++;
    		if( mxl < i + z[i] - 1 ) pos = i, mxl = i + z[i] - 1;
    	}
    }
    void get(char *S, int lenS, char *T, int lenT, int *f) {
    	for(int i=0;i<lenS;i++) str[i] = S[i];
    	str[lenS] = 1;
    	for(int i=0;i<lenT;i++) str[lenS+1+i] = T[i];
    	getZ(lenS + lenT + 1);
    	for(int i=0;i<lenT;i++) f[i] = z[lenS+1+i];
    }
    
    int n, m; ll T[2][MAXM + 5];
    int lowbit(int x) {return (x & -x);}
    void add(int x, ll d, int t) {
    	for(int i=x;i<=m;i+=lowbit(i))
    		T[t][i] += d;
    }
    void modify(int l, int r, ll d) {
    	add(l, d, 0), add(l, d*l, 1);
    	add(r + 1, -d, 0), add(r + 1, -d*(r + 1), 1);
    }
    ll sum(int x, int t) {
    	ll ret = 0;
    	for(int i=x;i;i-=lowbit(i))
    		ret += T[t][i];
    	return ret;
    }
    ll query(int l, int r) {
    	ll A = l*sum(l - 1, 0) - sum(l - 1, 1);
    	ll B = (r + 1)*sum(r, 0) - sum(r, 1);
    	return B - A;
    }
    
    char a[MAXN + 5], b[MAXN + 5], s[MAXM + 5];
    int af[MAXN + 5], bf[MAXN + 5];
    int main() {
    	scanf("%d%d%s%s%s", &n, &m, a, b, s);
    	get(s, m, a, n, af);
    	reverse(b, b + n), reverse(s, s + m);
    	get(s, m, b, n, bf);
    	reverse(bf, bf + n);
    	ll ans = 0;
    	for(int i=n-1;i>=0;i--) {
    		modify(max(m - bf[i], 1), m - 1, 1);
    		if( i + m - 1 < n )
    			modify(max(m - bf[i + m - 1], 1), m - 1, -1);
    		ans += query(1, af[i]);
    	}
    	printf("%lld
    ", ans);
    }
    

    @details@

    小清新的题目。

    差点忘了树状数组的区间加与区间求和怎么写了。。。

  • 相关阅读:
    关于Maya Viewport 2.0 API 开发的介绍视频
    春节大假
    Some tips about the life cycle of Maya thread pool
    Can I compile and run Dx11Shader for Maya 2015 on my side?
    How to get current deformed vertex positions in MoBu?
    想加入全球首届的 欧特克云加速计划吗?
    三本毕业(非科班),四次阿里巴巴面试,终拿 offer(大厂面经)
    mac、window版编辑器 webstorm 2016... 永久破解方法。
    node 搭载本地代理,处理web本地开发跨域问题
    js 一维数组,转成嵌套数组
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/12407978.html
Copyright © 2020-2023  润新知