1. 程式人生 > >HDU 5730 FFT + 分治

HDU 5730 FFT + 分治

題目連結

題意: 給定一個數組aa,定義a[i]a[i]表示連續ii個珍珠可以裝飾的方案數,求n個珍珠的項鍊可以裝飾的方案總數。

思路: 定義: F[i]F[i]ii個珍珠的項鍊可以裝飾的方案總數 則很明顯是一個動態規劃,得: F[0]=1F[0] = 1 F[i]=j=1ia[j]F[ij]F[i] = \sum_{j=1}^i a[j]*F[i-j]

可見維護的時間複雜度是O(n2)O(n^2) 可以利用分治+FFT, 每次合併區間時,計算左半區間對右半區間的貢獻。 時間複雜度:O(nlog2

(n))O(n \log^2(n))

程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 524300, P = 313, M = 1000;
int n, i, j, k, pos[N], A[N], B[N], C[N], F[N], Q[N];
namespace FFT{
struct comp{
    long double r, i;comp(long
double _r=0, long double _i=0){r=_r; i=_i;} comp operator + (const comp x){return comp(r+x.r, i+x.i);} comp operator - (const comp x){return comp(r-x.r, i-x.i);} comp operator * (const comp x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);} comp conj(){return comp(r, -i);} }A[N], B[N]; int a0[N]
, b0[N], a1[N], b1[N]; const long double pi = acos(-1.0); void FFT(comp a[], int n, int t){ for (int i = 1; i < n; i++) if (i < pos[i]) swap(a[i], a[pos[i]]); for (int d = 0; (1<<d) < n; d++) { int m = 1<<d, m2 = m<<1; long double o = pi*2/m2*t;comp _w(cos(o), sin(o)); for (int i = 0; i < n; i += m2) { comp w(1,0); for (int j = 0; j < m; j++) { comp &A = a[i+j+m], &B = a[i+j], t = w*A; A = B - t; B = B + t; w = w * _w; } } } if (t == -1) for (int i=0; i < n; i++) a[i].r /= n; } void mul(int *a, int *b, int *c){ int i, j; for (i = 0; i < k; i++) A[i] = comp(a[i], b[i]); FFT(A, k, 1); for (i = 0; i < k; i++) { j = (k-i)&(k-1); B[i] = (A[i]*A[i] - (A[j]*A[j]).conj()) * comp(0, -0.25); } FFT(B, k, -1); for (i = 0; i < k; i++) c[i] = ((long long)(B[i].r + 0.5)) % P; } void mulmod(int *a, int *b, int *c){ int i; for (i = 0; i < k; i++) a0[i] = a[i]/M, b0[i] = b[i]/M; for (mul(a0, b0, a0), i=0; i<k; i++) { c[i] = 1LL*a0[i]*M*M%P; a1[i] = a[i]%M, b1[i] = b[i] % M; } for (mul(a1, b1, a1), i=0; i<k; i++) { c[i] = (a1[i]+c[i])%P, a0[i]=(a0[i]+a1[i])%P; a1[i]=a[i]/M+a[i]%M, b1[i]=b[i]/M+b[i]%M; } for (mul(a1, b1, a1), i = 0; i < k; i++) c[i] = (1LL*M*(a1[i]-a0[i]+P)+c[i])%P; } } void Init(int len){ for (k = 1; k < len; k<<=1); j = __builtin_ctz(k) - 1; for (i = 0; i < k; i++) pos[i] = pos[i>>1]>>1|((i&1)<<j); } void CDQ(int l, int r){ if (l >= r) return; int mid = (l+r)>>1; CDQ(l, mid); Init(r-l+1); for (int i = 0; i < k; i++) A[i] = B[i] = 0; for (int i = l; i <= mid; i++) A[i-l] = F[i]; for (int i = 0; i <= r-l; i++) B[i] = Q[i]; FFT::mulmod(A, B, C); for (int i = mid+1; i <= r; i++) F[i] = (F[i] + C[i-l]) % P; CDQ(mid + 1, r); } int main(){ while (~scanf("%d", &n) && n) { for (i = 1; i <= n; i++) { int x; scanf("%d", &x); F[i] = Q[i] = x; } CDQ(0, n); printf("%d\n", (F[n]+P) % P); } return 0; }