zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    Magicodes.IE之花式导出
    Magicodes.IE之导入导出筛选器
    Magicodes.IE 2.3重磅发布——.NET Core开源导入导出库
    快速配置Azure DevOps代理服务器
    如何做好一个开源项目之徽章(二)
    使用Seq搭建免费的日志服务
    SpringBoot + SpringCloud Hystrix 实现服务熔断
    dedecms从word复制粘贴公式
    CuteEditor从word复制粘贴公式
    TinyMCE从word复制粘贴公式
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5236847.html
Copyright © 2011-2022 走看看