zoukankan      html  css  js  c++  java
  • bzoj2287

    背包+fft

    既然要不选一个东西,那么我们求出前缀背包和后缀背包,每次答案就是f[i-1][w]*g[i+1][j-w]

    但是这样复杂度还是n^3,跑不过,但是我们发现上面那个东西不就是个裸卷积吗,直接上fft,但是wa了...

    wa的程序,大概是精度问题吧

    #include<bits/stdc++.h>
    using namespace std;
    #define pi acos(-1)
    const int N = 3010;
    int n, m, L, x, nn, mm;
    int r[N * 4], f[N][N], g[N][N], w[N];
    complex<double> a[N * 4], b[N * 4];
    void fft(complex<double> *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)
        {
            complex<double> t(cos(pi / i), f * sin(pi / i));
            for(int p = i << 1, j = 0; j < n; j += p)
            {
                complex<double> w(1, 0);
                for(int k = 0; k < i; ++k, w *= t)
                {
                    complex<double> x = a[j + k], y = w * a[j + k + i];
                    a[j + k] = x + y; a[j + k + i] = x - y;
                }
            } 
        } 
    }
    int main()
    {
        scanf("%d%d", &nn, &mm);
        for(int i = 1; i <= nn; ++i) scanf("%d", &w[i]);
        f[0][0] = 1;
        for(int i = 1; i <= nn; ++i)
            for(int j = 0; j <= mm; ++j)
            {
                f[i][j] = f[i - 1][j];
                if(j >= w[i]) f[i][j] = (f[i][j] + f[i - 1][j - w[i]]) % 10;
            }
        g[nn + 1][0] = 1; 
        for(int i = nn; i; --i)
            for(int j = 0; j <= mm; ++j)
            {
                g[i][j] = g[i + 1][j];
                if(j >= w[i]) g[i][j] = (g[i][j] + g[i + 1][j - w[i]]) % 10;
            }
        for(int i = 1; i <= nn; ++i)
        {
            for(int j = 1; j <= mm; ++j) 
            {
                L = 0;
                m = 2 * j + 2;
                for(int k = 0; k <= m; ++k) a[k] = b[k] = 0;
                for(int k = 0; k <= j; ++k) 
                {
                    a[k] = f[i - 1][k];
                    b[k] = g[i + 1][k];
                }
                for(n = 1; n <= m; n <<= 1) ++L; 
                for(int k = 0; k < n; ++k) r[k] = (r[k >> 1] >> 1) | ((k & 1) << (L - 1));
                fft(a, 1);
                fft(b, 1);
                for(int k = 0; k <= n; ++k) a[k] = a[k] * b[k];
                fft(a, -1);
                int ans = (int)(a[j].real() / (double)n + 0.5);
                printf("%d", ans % 10);
            }
            puts("");
        }
        return 0;
    }
    View Code

     写了一个正解

    f[i]:装满i的方案数

    c[i][j]:装满j不用i的方案数

    j<w[i],自然c[i][j]=f[j],因为w[i]装不下,不可能选

    j>=w[i],c[i][j]=f[j]-c[i][j-w[i]],在j-w[i]填上一个w[i]就是j,表示选到第i个物品一定选了i的方案数,相减就是不选的方案数

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 2010;
    int n, m;
    int w[N], c[N], f[N];
    int main()
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) scanf("%d", &w[i]);
        f[0] = 1;
        for(int i = 1; i <= n; ++i)
            for(int j = m; j >= w[i]; --j)
                f[j] = (f[j] + f[j - w[i]]) % 10;
        for(int i = 1; i <= n; ++i)
        {
            for(int j = 0; j <= m; ++j)
            {
                if(j >= w[i]) c[j] = (f[j] - c[j - w[i]] % 10 + 10) % 10;
                else c[j] = f[j];
                if(j > 0) printf("%d", c[j]);
            }
            puts("");
        }
        return 0;
    }
    
    View Code
  • 相关阅读:
    Inside Dynamics Axapta源代码赏析(五)
    Inside Dynamics Axapta源代码赏析(二)
    PHP查询显示关键字为红色
    textarea自适应高度
    背景图只显示一次,不循环,另外还有一个是PHP下的换行显示
    PHP格式化时间,形如(Wed 30,Jul 2008)
    实现页面加载中。。
    c++关于设置精度
    HDOJ 2662
    live Messenger
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7396396.html
Copyright © 2011-2022 走看看