萬徑人蹤滅(FFT manacher)

2022-05-05 17:36:09 字數 2397 閱讀 3117

傳送門

這題……我覺得像我這樣的菜雞選手難以想出來……

題目要求求出一些子串行,使得其關於某個位置是對稱的,而且不能是連續一段,求這樣的子串行的個數。這個直接求很困難,但是我們可以先求出所有關於某個位置對稱的子串行,最後減去子串的個數。

子串個數可以用\(manacher\)求,至於子串行的話,我們假設以第\(i\)位為中心,那麼如果兩邊有\(x\)對相同的字元,那麼這個位置對答案的貢獻就是\(2^x-1\)或者\(2^(x+1)-1\)。(因為有可能回文串的長度是偶數,也就是不存在中間點)

考慮怎麼求\(x_i\)。\(x_i\)的形式可以寫成如下的形式:

\[\sum_^ic[i-j] == c[i+j]

\]發現這個式子非常像卷積的形式。那麼我們先初始化兩個序列,第乙個序列是原字串為『a』,對應位置為1,第二個是原字串為'b',對應位置是1,剩下都是0。這樣結果就轉化為如下形式:

\[\sum_^i a(i-j) * a(i+j) + b(i-j) * b(i+j)

\]然後讓他們自己和自己乘起來,結果相加一下,然後因為卷積會重複把元素計算兩遍,所以要+1再/2.

這樣得到的各項係數就是各項\(x_i\),我們就可以用快速冪計算。算完之後減去\(manacher\)求出的子串個數即可。

看一下**。

#include#include#include#include#include#include#include#include#include#define rep(i,a,n) for(int i = a;i <= n;i++)

#define per(i,n,a) for(int i = n;i >= a;i--)

#define enter putchar('\n')

#define fr friend inline

#define y1 poj

#define mp make_pair

#define pr pair#define fi first

#define sc second

#define pb push_back

#define i puts("bug")

using namespace std;

typedef long long ll;

const int m = 200005;

const int inf = 1000000009;

const double eps = 1e-7;

const double pi = acos(-1);

const ll mod = 1e9+7;

int read()

while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();

return ans * op;

}struct comp

comp(double kx,double ky)

fr comp operator + (const comp &a,const comp &b) ;}

fr comp operator - (const comp &a,const comp &b) ;}

fr comp operator * (const comp &a,const comp &b) ;}

}a[m<<1],b[m<<1],kx,ky;

int n,len = 1,l,p[m<<1],rev[m<<1];

char s[m<<1],c[m];

ll tot,d[m<<1],ans;

int change()

void manacher()

}void fft(comp *a,int f)}}

}ll qpow(ll a,ll b)

return p;

}int main()

while(len <= n << 1) len <<= 1,l++;

//i;

rep(i,0,len-1) rev[i] = (rev[i>>1] >> 1) | ((i&1) << (l-1));

fft(a,1),fft(b,1);

rep(i,0,len-1) a[i] = a[i] * a[i] + b[i] * b[i];

fft(a,-1);

rep(i,0,len-1) d[i] = ((ll)floor(a[i].x / len + 0.5) + 1) >> 1;

rep(i,0,len-1) ans += (qpow(2,d[i]) - 1),ans %= mod;

manacher(),ans -= tot,ans %= mod;

while(ans < 0) ans += mod;

printf("%lld\n",ans);

return 0;

}

BZOJ3160 萬徑人蹤滅

對於每個可以作為對稱軸的位置,我們算出以其為對稱軸有多少對位置和字元是對稱的,設為t i 若不考慮不能連續,則我們可以從這t i 對里任選出來任意對,都是可行的答案,且不重不漏,所以不考慮不能連續的情況的答案為sigma 2 t i 1,考慮不能是連續子串,再減去回文子串的數量即可 回文子串數量ma...

20178 27 萬徑人蹤滅 思考記錄

字串的題也可以fft 只要能化成卷積的形式就都可以fft 比如這裡的回文 對乙個位置 1 1 2 2 他們和相等,所以對a跑一邊,對b跑一遍,就相當於建出n次多項式然後求係數 注意manacher不要寫錯,漏寫最後一句 注意fft最後一句要寫在外面 碼 include include include...

BZOJ 3160 萬徑人蹤滅

給定乙個由 a 和 b 構成的字串,求不連續回文子串行的個數。正難則反我們考慮容斥。對於連續的回文字串顯然是一次馬拉車就可以很好的求出來的,那我們設f i 表示以i為中心的對稱字元對數量,顯然答案就是 2 n 1 12f i 1 那麼我們的問題就轉變成了怎麼求出f i 我們考慮當這個字元為a的時候做...