1. 程式人生 > >hdu5730 Shell Necklace 【分治fft】

hdu5730 Shell Necklace 【分治fft】

nec inline 直接 LG 表示 char 劃分 source 處理

題目

簡述:

有一段長度為n的貝殼,將其劃分為若幹段,給出劃分為每種長度的方案數,問有多少種劃分方案

題解

\(f[i]\)表示長度為\(i\)時的方案數
不難得dp方程:
\[f[i] = \sum\limits_{j=0}^{i} a[j] * f[i - j]\]

考慮轉移
直接轉移是\(O(n^2)\)
如何優化?
容易發現這個轉移方程非常特別,是一個卷積的形式
考慮fft

分治fft

分治fft解決的就是這樣一個轉移方程的快速計算的問題
\[f[i] = \sum\limits_{j=0}^{i} a[j] * f[i - j]\]

考慮cdq分治的模式:
我們先處理左半區間,然後用左半區間的\(f[i]\)

來更新右半區間的答案
具體地,左半區間對右邊一個位置\(r\)的貢獻是:
\[\sum\limits_{i=l}^{mid} f[i] * a[r - i]\]
也是一個卷積的形式,為多項式乘積的第\(r\)
如此我們便可以用\(f[i]\)\(a[i]\)構造兩個多項式,作fft,然後直接將相應位置的值累加到右半邊相應位置的\(f[i]\)中去

我們便解決了這道題

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts(""); using namespace std; const int maxn = 400005,maxm = 100005,INF = 1000000000,P = 313; inline int
read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } const double pi = acos(-1); struct E{ double r,i; E(){} E(double a,double b):r(a),i(b){} E operator =(const int& b){ r = b; i = 0; return *this; } }; inline E operator +(const E& a,const E& b){ return E(a.r + b.r,a.i + b.i); } inline E operator -(const E& a,const E& b){ return E(a.r - b.r,a.i - b.i); } inline E operator *(const E& a,const E& b){ return E(a.r * b.r - a.i * b.i,a.r * b.i + b.r * a.i); } inline E operator *=(E& a,const E& b){ return (a = a * b); } inline E operator /(E& a,const double& b){ return E(a.r / b,a.i / b); } inline E operator /=(E& a,const double& b){ return (a = a / b); } int n,m,L,R[maxn]; void fft(E* a,int f){ for (int i = 0; i < n; i++) if (i < R[i]) swap(a[i],a[R[i]]); for (int i = 1; i < n; i <<= 1){ E wn(cos(pi / i),f * sin(pi / i)); for (int j = 0; j < n; j += (i << 1)){ E w(1,0); for (int k = 0; k < i; k++,w *= wn){ E x = a[j + k],y = w * a[j + k + i]; a[j + k] = x + y; a[j + k + i] = x - y; } } } if (f == -1) for (int i = 0; i < n; i++) a[i] /= n; } E A[maxn],B[maxn]; int N,a[maxn],f[maxn]; void solve(int l,int r){ if (l == r){ f[l] = (f[l] + a[l]) % P; return; } int mid = l + r >> 1; solve(l,mid); n = mid - l + 1; for (int i = 0; i < n; i++) A[i] = f[l + i]; m = r - l + 1; for (int i = 0; i < m; i++) B[i] = a[i + 1]; m = n + m; L = 0; for (n = 1; n <= m; n <<= 1) L++; for (int i = 0; i < n; i++) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1)); fft(A,1); fft(B,1); for (int i = 0; i < n; i++) A[i] *= B[i]; fft(A,-1); for (int i = mid + 1; i <= r; i++){ f[i] = (f[i] + (int)floor(A[i - l - 1].r + 0.5) % P) % P; } for (int i = 0; i < n; i++) A[i] = B[i] = 0; solve(mid + 1,r); } int main(){ while ((~scanf("%d",&N)) && N){ for (int i = 1; i <= N; i++){ a[i] = read() % P; f[i] = 0; } solve(1,N); printf("%d\n",f[N]); } return 0; }

hdu5730 Shell Necklace 【分治fft】