BZOJ 3160 FFT+马拉车
题意显然
ans=回文子序列数目 - 回文子串数目
回文子串直接用马拉车跑出来
回文子序列一开始总是不知道怎么求 (太蠢了)
后面看了题解
构造一个神奇的卷积
(这个是我盗的图)地址
后面还有一些细节需要处理出 f[x] (f[x] 表示 x左右相等的个数)
通常我们需要的情况是 两个函数相乘 这里是s[x-i] == s[x+i] 分类讨论就行了 变成1*1=1的形式
所以要a=1 b=0 和 a=0 b=1都算一次
这里长度扩展了一倍 表示 当 i 是奇数时表示对称轴是元素 ,偶数表示对称轴是两个元素的间隔
根据二项式定理 求出每一个f[x] 的贡献 expmod ( 2, ( cnt[i] + 1 ) >> 1 ) - 1
还有最后一个细节 相减的时候要记得加上mod 再取模
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <cmath> 5 #include <algorithm> 6 #include <set> 7 #include <iostream> 8 #include <map> 9 #include <stack> 10 #include <string> 11 #include <vector> 12 #define pi acos(-1.0) 13 #define eps 1e-9 14 #define fi first 15 #define se second 16 #define rtl rt<<1 17 #define rtr rt<<1|1 18 #define bug printf("******\n") 19 #define mem(a,b) memset(a,b,sizeof(a)) 20 #define name2str(x) #x 21 #define fuck(x) cout<<#x" = "<<x<<endl 22 #define f(a) a*a 23 #define sf(n) scanf("%d", &n) 24 #define sff(a,b) scanf("%d %d", &a, &b) 25 #define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c) 26 #define sffff(a,b,c,d) scanf("%d %d %d %d", &a, &b, &c, &d) 27 #define pf printf 28 #define FRE(i,a,b) for(i = a; i <= b; i++) 29 #define FREE(i,a,b) for(i = a; i >= b; i--) 30 #define FRL(i,a,b) for(i = a; i < b; i++)+ 31 #define FRLL(i,a,b) for(i = a; i > b; i--) 32 #define FIN freopen("data.txt","r",stdin) 33 #define gcd(a,b) __gcd(a,b) 34 #define lowbit(x) x&-x 35 #define rep(i,a,b) for(int i=a;i<b;++i) 36 #define per(i,a,b) for(int i=a-1;i>=b;--i) 37 using namespace std; 38 typedef long long LL; 39 typedef unsigned long long ULL; 40 const int maxn = 3e5 + 7; 41 const int maxm = maxn * 4; 42 const int mod = 1e9 + 7; 43 int n, m, a[maxn], b[maxn]; 44 int len, res[maxm], mx; //开大4倍 45 struct cpx { 46 long double r, i; 47 cpx ( long double r = 0, long double i = 0 ) : r ( r ), i ( i ) {}; 48 cpx operator+ ( const cpx &b ) { 49 return cpx ( r + b.r, i + b.i ); 50 } 51 cpx operator- ( const cpx &b ) { 52 return cpx ( r - b.r, i - b.i ); 53 } 54 cpx operator* ( const cpx &b ) { 55 return cpx ( r * b.r - i * b.i, i * b.r + r * b.i ); 56 } 57 } va[maxm], vb[maxm]; 58 void rader ( cpx F[], int len ) { //len = 2^M,reverse F[i] with F[j] j为i二进制反转 59 int j = len >> 1; 60 for ( int i = 1; i < len - 1; ++i ) { 61 if ( i < j ) swap ( F[i], F[j] ); // reverse 62 int k = len >> 1; 63 while ( j >= k ) j -= k, k >>= 1; 64 if ( j < k ) j += k; 65 } 66 } 67 void FFT ( cpx F[], int len, int t ) { 68 rader ( F, len ); 69 for ( int h = 2; h <= len; h <<= 1 ) { 70 cpx wn ( cos ( -t * 2 * pi / h ), sin ( -t * 2 * pi / h ) ); 71 for ( int j = 0; j < len; j += h ) { 72 cpx E ( 1, 0 ); //旋转因子 73 for ( int k = j; k < j + h / 2; ++k ) { 74 cpx u = F[k]; 75 cpx v = E * F[k + h / 2]; 76 F[k] = u + v; 77 F[k + h / 2] = u - v; 78 E = E * wn; 79 } 80 } 81 } 82 if ( t == -1 ) //IDFT 83 for ( int i = 0; i < len; ++i ) F[i].r /= len; 84 } 85 void Conv ( cpx a[], cpx b[], int len ) { //求卷积 86 FFT ( a, len, 1 ); 87 FFT ( b, len, 1 ); 88 for ( int i = 0; i < len; ++i ) a[i] = a[i] * b[i]; 89 FFT ( a, len, -1 ); 90 } 91 void gao () { 92 len = 1; 93 mx = n + m; 94 while ( len <= mx ) len <<= 1; //mx为卷积后最大下标 95 for ( int i = 0; i < len; i++ ) va[i].r = va[i].i = vb[i].r = vb[i].i = 0; 96 for ( int i = 0; i < n; i++ ) va[i].r = a[i]; //根据题目要求改写 97 for ( int i = 0; i < m; i++ ) vb[i].r = b[i]; //根据题目要求改写 98 Conv ( va, vb, len ); 99 for ( int i = 0; i < len; ++i ) res[i] += ( LL ) floor ( va[i].r + 0.5 ); 100 } 101 char Ma[maxn * 2]; 102 int Mp[maxn * 2]; 103 int Manacher ( char s[], int len ) { 104 int l = 0, ret = 0; 105 Ma[l++] = '$'; 106 Ma[l++] = '#'; 107 for ( int i = 0; i < len; i++ ) { 108 Ma[l++] = s[i]; 109 Ma[l++] = '#'; 110 } 111 Ma[l] = 0; 112 int mx = 0, id = 0; 113 for ( int i = 0; i < l; i++ ) { 114 Mp[i] = mx > i ? min ( Mp[2 * id - i], mx - i ) : 1; 115 while ( Ma[i + Mp[i]] == Ma[i - Mp[i]] ) Mp[i]++; 116 if ( i + Mp[i] > mx ) { 117 mx = i + Mp[i]; 118 id = i; 119 } 120 ret += Mp[i] >> 1, ret %= mod; 121 } 122 return ret % mod; 123 } 124 LL expmod ( LL a, LL b ) { 125 LL res = 1; 126 while ( b ) { 127 if ( b & 1 ) res = res * a % mod; 128 a = a * a % mod; 129 b = b >> 1; 130 } 131 return res % mod; 132 } 133 char s[maxn]; 134 int cnt[maxn]; 135 int main() { 136 // FIN; 137 scanf ( "%s", s + 1 ); 138 n = m = strlen ( s + 1 ); 139 LL ans = 0, temp = Manacher ( s + 1, n ); 140 n++, m++; 141 for ( int i = 1 ; i < n ; i++ ) if ( s[i] == 'a' ) a[i] = 1, b[i] = 1; 142 gao(); 143 for ( int i = 1 ; i <= 2 * ( n - 1 ) ; i++ ) cnt[i] += res[i]; 144 mem ( a, 0 ), mem ( b, 0 ), mem ( res, 0 ); 145 for ( int i = 1 ; i < n ; i++ ) if ( s[i] == 'b' ) a[i] = 1, b[i] = 1; 146 gao(); 147 for ( int i = 1 ; i <= 2 * ( n - 1 ) ; i++ ) cnt[i] += res[i]; 148 for ( int i = 1 ; i <= 2 * ( n - 1 ) ; i++ ) 149 ans = ( ans + expmod ( 2, ( cnt[i] + 1 ) >> 1 ) - 1 ) % mod; 150 printf ( "%lld\n", ( ans - temp + mod ) % mod ); 151 return 0; 152 }