zoukankan      html  css  js  c++  java
  • HDU 5730

    题意:

      给出连续的1-n个珠子的涂色方法 a[i](1<=i<=n), 问长度为n的珠链共有多少种涂色方案

    分析:

      可以得到DP方程: DP[n] = ∑(i=1,n) (DP[n-i]*a[i]).

      该方程为卷积形式,故 CDQ + FFT

      

      CDQ: 将 [l,r] 二分, 先得到[l,mid]的答案,再更新[l,mid]对[mid+1,r]的贡献.

           对任意 DP[j](mid+1 <= j <= r), [l,mid] 对其贡献为 ∑(i=l,mid) (DP[i]*a[j - i]) , 即多项式 DP 与 a 相乘后次数为j项.

      FFT: 优化多项式相乘.

    (1 和 l 看不清的也就这破博客园了,代码还是粘下来的好,= =)

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 using namespace std;
      6 const double PI = 4 * atan(1.0);
      7 const int MAXN = 200005;
      8 const int MOD = 313;
      9 struct Complex
     10 {
     11     double x, y;
     12     Complex(double xx = 0.0, double yy = 0.0) : x(xx), y(yy) {}
     13     Complex operator - (const Complex &b) const 
     14     {
     15         return Complex(x - b.x, y - b.y);
     16     }
     17     Complex operator + (const Complex &b) const
     18     {
     19         return Complex(x + b.x, y + b.y);
     20     }
     21     Complex operator * (const Complex &b) const
     22     {
     23         return Complex(x*b.x - y*b.y, x*b.y + y*b.x);
     24     }
     25 };
     26 void Change(Complex y[], int len)
     27 {
     28     int i, j, k;
     29     for (i = 1, j = len/2; i < len-1; i++)
     30     {
     31         if (i < j) swap(y[i], y[j]);
     32         k = len / 2;
     33         while (j >= k)
     34         {
     35             j -= k;
     36             k /= 2;
     37         }
     38         if (j < k) j += k;
     39     }
     40 }
     41 void FFT(Complex y[], int len,int on)
     42 {
     43     Change(y, len);
     44     for (int h = 2; h <= len; h <<= 1)
     45     {
     46         Complex wn( cos(-on*2*PI/h), sin(-on*2*PI/h) );
     47         for (int j = 0; j < len; j +=h)
     48         {
     49             Complex w(1, 0);
     50             for (int k = j; k < j + h/2; k++)
     51             {
     52                 Complex u = y[k];
     53                 Complex t = w * y[k + h/2];
     54                 y[k] = u + t;
     55                 y[k + h/2] = u - t;
     56                 w = w * wn;                
     57             }
     58         }
     59     } 
     60     if (on == -1)
     61         for (int i = 0; i < len; i++)
     62             y[i].x /= len;
     63 }
     64 int t, n;
     65 Complex x[MAXN], y[MAXN];
     66 int a[MAXN/2], dp[MAXN/2];
     67 void CDQ(int l, int r)
     68 {
     69     if (l == r) { dp[l] = (dp[l] + a[l]) % MOD; return; } 
     70     int mid = (l + r) >> 1; 
     71     CDQ(l, mid);//处理前半段 
     72     int len = 1, len1 = mid - l + 1, len2 = r - l + 1;
     73     while(len < len2) len <<= 1;
     74     for (int i = 0; i < len1; i++) x[i] = Complex(dp[i + l], 0);
     75     for (int i = len1; i < len; i++) x[i] = Complex(0, 0);
     76     for (int i = 0; i < len2; i++) y[i] = Complex(a[i], 0);
     77     for (int i = len2; i < len; i++) y[i] = Complex(0, 0); 
     78     FFT(x, len, 1);
     79     FFT(y, len, 1);
     80     for (int i = 0; i < len; i++) x[i] = x[i] *y[i];
     81     FFT(x, len, -1);
     82     for (int i = mid+1; i <= r; i++)//更新贡献 
     83     {
     84         dp[i] = (int)(dp[i] + x[i - l].x + 0.5) %MOD;
     85     }
     86     CDQ(mid + 1, r);//处理后半段 
     87 }
     88 int main()
     89 {
     90     while(~scanf("%d",&n) && n)
     91     {
     92         for (int i = 1; i <= n; i++)
     93         {
     94             scanf("%d",&a[i]);
     95             a[i] %= MOD;
     96             dp[i] = 0;
     97         }
     98         CDQ(1, n);
     99         printf("%d
    ", dp[n]);
    100     }
    101 }
    我自倾杯,君且随意
  • 相关阅读:
    冒泡排序
    三种for循环遍历
    打印一年中的月历
    基于主主复制的mysql双机热备+keepalived实现高可用性
    docker实现apache+php容器和mysql容器独立运行
    XML和JSON
    PHP表单
    【翻译-Docker】Post-installation steps for Linux
    【翻译】docker install
    小计划
  • 原文地址:https://www.cnblogs.com/nicetomeetu/p/5734820.html
Copyright © 2011-2022 走看看