HDU5730 Shell Necklace

题面

题意简述

一段长为\(i\)的项链有\(a_i\)中装饰方法,问长度为\(n\)的项链有多少种装饰方式。

答案对\(313\)取膜

题解

\(f[i]\)表示\(\mathcal{DP}\)到第\(i\)位有多少种方式
\[ f[i] = \sum_{j=1}^{i-1} f[j]a[i - j] \]
分治\(\mathcal{FFT}\)走起

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define clear(x, y) memset(x, y, sizeof(x))

inline int read()
{
    int data = 0, w = 1; char ch = getchar();
    while(ch != '-' && (!isdigit(ch))) ch = getchar();
    if(ch == '-') w = -1, ch = getchar();
    while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
    return data * w;
}

const int maxn(3e5 + 10), Mod(313);
const double pi(acos(-1));
struct complex { double x, y; };
inline complex operator + (const complex &lhs, const complex &rhs)
    { return (complex) {lhs.x + rhs.x, lhs.y + rhs.y}; }
inline complex operator - (const complex &lhs, const complex &rhs)
    { return (complex) {lhs.x - rhs.x, lhs.y - rhs.y}; }
inline complex operator * (const complex &lhs, const complex &rhs)
{
    return (complex) {lhs.x * rhs.x - lhs.y * rhs.y,
        lhs.y * rhs.x + lhs.x * rhs.y};
}

template<int opt> void FFT(complex *p, int n)
{
    for(RG int i = 1; i < n; i <<= 1)
    {
        complex rot = (complex) {cos(pi / i), opt * sin(pi / i)};
        for(RG int j = 0; j < n; j += (i << 1))
        {
            complex w = (complex) {1, 0};
            for(RG int k = 0; k < i; ++k, w = w * rot)
            {
                complex x = p[j + k], y = w * p[i + j + k];
                p[j + k] = x + y, p[i + j + k] = x - y;
            }
        }
    }
}

void Mul(int n1, int n2, complex *a, complex *b, complex *c)
{
    static int n, m, r[maxn], P;
    for(m = n1 + n2, n = 1, P = -1; n <= m; n <<= 1, ++P);
    for(RG int i = n1; i < n; i++) a[i].x = a[i].y = 0.;
    for(RG int i = n2; i < n; i++) b[i].x = b[i].y = 0.;
    for(RG int i = 0; i < n; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << P);
    for(RG int i = 0; i < n; i++)
        if(i < r[i]) std::swap(a[i], a[r[i]]), std::swap(b[i], b[r[i]]);
    FFT<1>(a, n), FFT<1>(b, n);
    for(RG int i = 0; i < n; i++) c[i] = a[i] * b[i];
    for(RG int i = 0; i < n; i++) if(i < r[i]) std::swap(c[i], c[r[i]]);
    FFT<-1>(c, n);
    for(RG int i = 0; i < n; i++) c[i].x = c[i].x / n + .5;
}

int f[maxn], a[maxn], n;
void CDQ(int l, int r)
{
    static complex A[maxn], B[maxn], C[maxn];
    if(l == r) return (void) (f[l] = (f[l] + a[l]) % Mod);
    int mid = (l + r) >> 1; CDQ(l, mid);
    for(RG int i = l; i <= mid; i++) A[i - l].x = f[i], A[i - l].y = 0.;
    for(RG int i = 1; i <= r - l; i++) B[i - 1].x = a[i], B[i - 1].y = 0.;
    Mul(mid - l + 1, r - l, A, B, C);
    for(RG int i = mid + 1; i <= r; i++)
        f[i] = (f[i] + (int)C[i - (l + 1)].x) % Mod;
    CDQ(mid + 1, r);
}

int main()
{
    while(~scanf("%d", &n))
    {
        if(!n) break; clear(f, 0), f[0] = 1;
        for(RG int i = 1; i <= n; i++) a[i] = read() % Mod;
        CDQ(1, n); printf("%d\n", f[n]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cj-xxz/p/10330783.html