• Educational Codeforces Round 9 E. Thief in a Shop dp fft


    E. Thief in a Shop

    题目连接:

    http://www.codeforces.com/contest/632/problem/E

    Description

    A thief made his way to a shop.

    As usual he has his lucky knapsack with him. The knapsack can contain k objects. There are n kinds of products in the shop and an infinite number of products of each kind. The cost of one product of kind i is ai.

    The thief is greedy, so he will take exactly k products (it's possible for some kinds to take several products of that kind).

    Find all the possible total costs of products the thief can nick into his knapsack.

    Input

    The first line contains two integers n and k (1 ≤ n, k ≤ 1000) — the number of kinds of products and the number of products the thief will take.

    The second line contains n integers ai (1 ≤ ai ≤ 1000) — the costs of products for kinds from 1 to n.

    Output

    Print the only line with all the possible total costs of stolen products, separated by a space. The numbers should be printed in the ascending order.

    Sample Input

    3 2
    1 2 3

    Sample Output

    2 3 4 5 6

    Hint

    题意

    有n个数,然后这n个数里面选k个加起来

    问你一共能加出来多少种

    题解:

    多项式加法,加k次,问你最后的数是哪些,显然FFT模板,然后怼一波

    其实DP也是可以兹瓷的。

    dp[i]表示最少用多少个非a[1]能够构成a[1]*k+i的。

    DP代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e3+5;
    int n,k,a[maxn],dp[maxn*maxn];
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+n);
        n=unique(a+1,a+1+n)-(a+1);
        for(int i=2;i<=n;i++)
            a[i]=a[i]-a[1];
        for(int i=1;i<=k*a[n];i++)
            dp[i]=k+1;
        for(int i=2;i<=n;i++)
            for(int j=a[i];j<=k*a[i];j++)
                dp[j]=min(dp[j],dp[j-a[i]]+1);
        for(int i=0;i<=k*a[n];i++)
            if(dp[i]<=k)
                printf("%d ",a[1]*k+i);
        return 0;
    }
    

    FFT代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxn = 1<<21;
    const double PI = acos(-1.0);
    
    struct Virt
    {
        double r,i;
    
        Virt(double r = 0.0,double i = 0.0)
        {
            this->r = r;
            this->i = i;
        }
    
        Virt operator + (const Virt &x)
        {
            return Virt(r+x.r,i+x.i);
        }
    
        Virt operator - (const Virt &x)
        {
            return Virt(r-x.r,i-x.i);
        }
    
        Virt operator * (const Virt &x)
        {
            return Virt(r*x.r-i*x.i,i*x.r+r*x.i);
        }
    };
    
    //雷德算法--倒位序
    void Rader(Virt F[],int len)
    {
        int j = len >> 1;
        for(int i=1; i<len-1; i++)
        {
            if(i < j) swap(F[i], F[j]);
            int k = len >> 1;
            while(j >= k)
            {
                j -= k;
                k >>= 1;
            }
            if(j < k) j += k;
        }
    }
    
    //FFT实现
    void FFT(Virt F[],int len,int on)
    {
        Rader(F,len);
        for(int h=2; h<=len; h<<=1) //分治后计算长度为h的DFT
        {
            Virt wn(cos(-on*2*PI/h),sin(-on*2*PI/h));  //单位复根e^(2*PI/m)用欧拉公式展开
            for(int j=0; j<len; j+=h)
            {
                Virt w(1,0);            //旋转因子
                for(int k=j; k<j+h/2; k++)
                {
                    Virt u = F[k];
                    Virt t = w*F[k+h/2];
                    F[k] = u+t;      //蝴蝶合并操作
                    F[k+h/2] = u-t;
                    w = w*wn;      //更新旋转因子
                }
            }
        }
        if(on == -1)
            for(int i=0; i<len; i++)
                F[i].r /= len;
    }
    
    //求卷积
    void Conv(Virt F[],Virt G[],int len)
    {
        FFT(F,len,1);
        FFT(G,len,1);
        for(int i=0; i<len; i++)
            F[i] = F[i]*G[i];
        FFT(F,len,-1);
    }
    int mx = 0;
    bool dp[maxn];
    bool a[maxn];
    Virt K1[maxn],K2[maxn];
    void multiply(bool *A,bool *B,int l)
    {
        int len = 1;
        while(len<=l+1)len*=2;
        for(int i=0;i<len;i++)
        {
            K1[i].r=A[i];
            K1[i].i=0;
            K2[i].r=B[i];
            K2[i].i=0;
        }
        Conv(K1,K2,len);
        for(int i=0;i<=len;i++)
            A[i]=K1[i].r>0.5;
    }
    void solve(int k)
    {
        if(k==0)
        {
            dp[0]=true;
        }
        else if(k%2==1)
        {
            solve(k-1);
            multiply(dp,a,mx);
        }
        else
        {
            solve(k/2);
            multiply(dp,dp,mx);
        }
    }
    int main()
    {
        int n,k;
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            int x;scanf("%d",&x);
            a[x]=true;mx=max(mx,x);
        }
        mx*=k;
        solve(k);
        for(int i=1;i<=mx;i++)
            if(dp[i])printf("%d ",i);
        cout<<endl;
    }
  • 相关阅读:
    fmri资源站点
    spm教程
    linux下ntfs硬盘的加载
    Unix网络编程代码 第13章 守护进程和inetd超级服务器
    APUE16章的运行示例16-14
    Linux守护进程详解(init.d和xinetd)
    centos安装g++
    linux下daemon守护进程的实现(以nginx代码为例)
    Linux进程学习(孤儿进程和守护进程)
    Linux之TCPIP内核参数优化
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5236847.html
Copyright © 2020-2023  润新知