• [BZOJ3160]万径人踪灭


    [BZOJ3160]万径人踪灭

    试题描述

    输入

    输出

    见“输入

    输入示例

    见“输入

    输出示例

    见“输入

    数据规模及规定


    题解

    问题分为两部分:

    一. 对于每一个分界点(某个位置)或分界线(某两个位置中间),要求这么一个东西

    意思就是回文串要求左半部分与右半部分对称,那么找到这些对称的位置,每个位置有选择或者不选两种情况,所以是 2 的那么多次方。

    求法:因为原串只有 a, b 两种字符,所以把 a 设成 1,b 设成 0 求一次卷积,再把 b 设成 1,a 设成 0 求一次卷积,加起来即可。

    二. 排除连续的情况

    hash + 二分。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <stack>
    #include <vector>
    #include <queue>
    #include <cstring>
    #include <string>
    #include <map>
    #include <set>
    using namespace std;
    
    const int BufferSize = 1 << 16;
    char buffer[BufferSize], *Head, *Tail;
    inline char Getchar() {
    	if(Head == Tail) {
    		int l = fread(buffer, 1, BufferSize, stdin);
    		Tail = (Head = buffer) + l;
    	}
    	return *Head++;
    }
    int read() {
    	int x = 0, f = 1; char c = Getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    	return x * f;
    }
    
    #define maxn 260010
    #define MOD 1000000007
    #define ULL unsigned long long
    const double pi = acos(-1.0);
    int n;
    ULL hashl[maxn], hashr[maxn], hashl2[maxn], hashr2[maxn], id2[maxn], id3[maxn];
    char S[maxn];
    struct Complex {
    	double a, b;
    	Complex() { a = b = 0.0; }
    	Complex operator + (const Complex& t) const {
    		Complex ans;
    		ans.a = a + t.a;
    		ans.b = b + t.b;
    		return ans;
    	}
    	Complex operator - (const Complex& t) const {
    		Complex ans;
    		ans.a = a - t.a;
    		ans.b = b - t.b;
    		return ans;
    	}
    	Complex operator * (const Complex& t) const {
    		Complex ans;
    		ans.a = a * t.a - b * t.b;
    		ans.b = a * t.b + b * t.a;
    		return ans;
    	}
    	Complex operator *= (const Complex& t) {
    		*this = *this * t;
    		return *this;
    	}
    } a[maxn<<1], b[maxn<<1];
    
    int tar[maxn];
    void FFT(Complex* a, int n, int tp) {
    	for(int i = 0; i < n; i++) if(i < tar[i]) swap(a[i], a[tar[i]]);
    	for(int i = 1; i < n; i <<= 1) {
    		Complex w, wn; wn.a = cos(pi / i); wn.b = sin(pi / i) * tp;
    		for(int j = 0; j < n; j += (i << 1)) {
    			w.a = 1.0; w.b = 0.0;
    			for(int k = 0; k < i; k++) {
    				Complex t1 = a[j+k], t2 = a[j+k+i] * w;
    				a[j+k] = t1 + t2;
    				a[j+k+i] = t1 - t2;
    				w *= wn;
    			}
    		}
    	}
    	if(tp < 0) for(int i = 0; i <= n; i++) a[i].a = a[i].a / (double)n + .5;
    	return ;
    }
    
    ULL lstr(int l, int r) { l++, r++; return hashl[r] - hashl[l-1] * id2[r-l+1]; }
    ULL rstr(int l, int r) { l++, r++; return hashr[l] - hashr[r+1] * id2[r-l+1]; }
    ULL lstr2(int l, int r) { l++, r++; return hashl2[r] - hashl2[l-1] * id3[r-l+1]; }
    ULL rstr2(int l, int r) { l++, r++; return hashr2[l] - hashr2[r+1] * id3[r-l+1]; }
    
    int two[maxn], ans, Len;
    bool check(int i, int mid) {
    	int ll = (i >> 1) - mid + 1, lr = (i >> 1), rl = (i & 1) ? (i >> 1) + 1 : lr, rr = rl + mid - 1;
    	bool res = ll >= 0 && rr < Len && (rstr(ll, lr) == lstr(rl, rr)) && (rstr2(ll, lr) == lstr2(rl, rr));
    //	if((i >> 1) == 127) printf("%d(%c) %d(%c) %d(%c) %d(%c) %llu %llu	", ll, S[ll], lr, S[lr], rl, S[rl], rr, S[rr], rstr(ll, lr), lstr(rl, rr));
    	return ll >= 0 && rr < Len && rstr(ll, lr) == lstr(rl, rr) && rstr2(ll, lr) == lstr2(rl, rr);
    }
    int main() {
    	scanf("%s", S);
    	int m = strlen(S) - 1; Len = strlen(S);
    	
    	int L = 0;
    	for(n = 1; n <= (m << 1); n <<= 1) L++;
    	for(int i = 0; i < n; i++) tar[i] = (tar[i>>1] >> 1) | ((i & 1) << L - 1);
    	for(int i = 0; i <= m; i++) a[i].a = (double)(S[i] == 'a');
    	FFT(a, n, 1);
    	for(int i = 0; i <= n; i++) a[i] *= a[i];
    	for(int i = 0; i <= m; i++) b[i].a = (double)(S[i] == 'b');
    	FFT(b, n, 1);
    	for(int i = 0; i <= n; i++) b[i] *= b[i], a[i] = a[i] + b[i];
    	FFT(a, n, -1);
    	for(int i = 0; i <= (m << 1); i++) a[i].a = (double)((int)a[i].a + 1 >> 1), b[i].a = (double)((int)b[i].a + 1 >> 1);
    //	for(int i = 0; i <= (m << 1); i++) printf("%d ", (int)a[i].a); putchar('
    ');
    	
    	two[0] = 1;
    	for(int i = 1; i <= m; i++) {
    		two[i] = two[i-1] << 1;
    		if(two[i] > MOD) two[i] -= MOD;
    	}
    	hashl[0] = 0;
    	for(int i = 1; i <= m + 1; i++) hashl[i] = hashl[i-1] * 2 + S[i-1] - 'a';
    	hashr[m+2] = 0;
    	for(int i = m + 1; i; i--) hashr[i] = hashr[i+1] * 2 + S[i-1] - 'a';
    	id2[0] = 1;
    	for(int i = 1; i <= m + 1; i++) id2[i] = id2[i-1] * 2;
    	hashl2[0] = 0;
    	for(int i = 1; i <= m + 1; i++) hashl2[i] = hashl2[i-1] * 3 + S[i-1] - 'a';
    	hashr2[m+2] = 0;
    	for(int i = m + 1; i; i--) hashr2[i] = hashr2[i+1] * 3 + S[i-1] - 'a';
    	id3[0] = 1;
    	for(int i = 1; i <= m + 1; i++) id3[i] = id3[i-1] * 3;
    	m++, m <<= 1; int tmp = 0;
    	for(int i = 0; i <= m - 2; i++) {
    		ans += two[(int)a[i].a];
    		int l = 0, r = min((i >> 1) + 1, (i & 1) ? (m >> 1) - (i >> 1) : (m >> 1) - (i >> 1) + 1) + 1;
    		while(l < r - 1) {
    			int mid = l + r >> 1;
    			if(check(i, mid)) l = mid; else r = mid;
    		}
    		if(check(i, l + 1)) l++;
    		ans -= l + 1;
    		if(ans < 0) ans += MOD;
    		if(ans > MOD) ans -= MOD;
    	}
    	
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    /*
    abaabaa
    */
    

    当然也可以用 manacher。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxN 262150
    #define MOD 1000000007
    const double pi = acos(-1.0);
    
    char S[maxn], Str[maxn<<1];
    int Len[maxn<<1], alp[maxn<<1];
    
    struct Vec {
    	double x, y;
    	Vec() {}
    	Vec(double _, double __): x(_), y(__) {}
    	Vec operator + (const Vec& t) const { return Vec(x + t.x, y + t.y); }
    	Vec operator - (const Vec& t) const { return Vec(x - t.x, y - t.y); }
    	Vec operator * (const Vec& t) const { return Vec(x * t.x - y * t.y, x * t.y + t.x * y); }
    	Vec operator *= (const Vec& t) { *this = *this * t; return *this; }
    	Vec operator = (const bool& t) { this->x = t; this->y = 0; return *this; }
    } A[maxN], B[maxN];
    
    int tar[maxN];
    void FFT_init(int K) {
    	int n = 1 << K;
    	for(int i = 0; i < n; i++) {
    		tar[i] = 0;
    		for(int j = 0; j < K; j++) tar[i] = tar[i] << 1 | (i >> j & 1);
    	}
    	return ;
    }
    void FFT(Vec x[], int K, int fl) {
    	int n = 1 << K;
    	for(int i = 0; i < n; i++) if(i < tar[i]) swap(x[i], x[tar[i]]);
    	for(int i = 1; i <= K; i++) {
    		Vec w, wn(cos(2.0 * pi / (1 << i)), sin(2.0 * pi / (1 << i)) * fl);
    		for(int j = 0; j < n; j += (1 << i)) {
    			w = Vec(1, 0);
    			for(int k = j; k < j + (1 << i - 1); k++, w *= wn) {
    				Vec t1 = x[k], t2 = w * x[k+(1<<i-1)];
    				x[k] = t1 + t2;
    				x[k+(1<<i-1)] = t1 - t2;
    			}
    		}
    	}
    	return ;
    }
    
    int two[maxN];
    
    int main() {
    	scanf("%s", S);
    	int n = strlen(S);
    	for(int i = 0; i < n; i++) A[i] = S[i] == 'a', B[i] = S[i] == 'b';
    	
    	int m = (n << 1) - 1, K = 0;
    	for(n = 1; n < m; n <<= 1) K++;
    	FFT_init(K);
    	FFT(A, K, 1); FFT(B, K, 1);
    	for(int i = 0; i < n; i++) A[i] *= A[i], B[i] *= B[i];
    	FFT(A, K, -1); FFT(B, K, -1);
    	
    	two[0] = 1;
    	for(int i = 1; i <= n; i++) {
    		two[i] = two[i-1] << 1;
    		if(two[i] >= MOD) two[i] -= MOD;
    	}
    	int ans = 0;
    	for(int i = 0; i < m; i++) {
    		int a = A[i].x / n + .5, b = B[i].x / n + .5;
    		ans += two[a+b+1>>1] - 1;
    //		printf("%d %d %d
    ", a, b, a + b + 1 >> 1);
    		if(ans >= MOD) ans -= MOD;
    	}
    	
    	n = strlen(S);
    	for(int i = 1; i <= n; i++) Str[(i<<1)-1] = S[i-1], Str[i<<1] = '#'; n <<= 1;
    	for(int i = 1; i <= n; i++) alp[i] = alp[i-1] + ('a' <= Str[i] && Str[i] <= 'z');
    //	puts(Str + 1);
    	int mxp = 0;
    	for(int i = 1; i <= n; i++) {
    		int mxr = mxp + Len[mxp] - 1;
    		if(mxr >= i) Len[i] = max(min(Len[(mxp<<1)-i], mxr - i + 1), 1);
    		else Len[i] = 1;
    		while(1 <= i - Len[i] + 1 && i + Len[i] - 1 <= n && Str[i-Len[i]+1] == Str[i+Len[i]-1]) Len[i]++;
    		Len[i]--;
    		if(mxr < i + Len[i] - 1) mxp = i;
    //		printf("%d%c", Len[i], i < n ? ' ' : '
    ');
    		ans -= alp[i+Len[i]-1] - alp[i-1];
    		if(ans < 0) ans += MOD;
    	}
    	
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    AtCoder Grand Contest 032-B
    AtCoder Grand Contest 032 A
    高橋君とカード / Tak and Cards AtCoder
    Divisibility by 25 CodeForces
    Fire Again CodeForces
    cctype函数 (字符类型判断)
    蓝桥杯--- 历届试题 国王的烦恼 (并查集)
    蓝桥杯---买不到的数目
    算法课(经典贪心)
    完美的数字
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5728349.html
Copyright © 2020-2023  润新知