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;
    }
  • 相关阅读:
    ubuntu 15.04默认root用户登陆
    hive的not in
    Spark 1.4.1中Beeline使用的gc overhead limit exceeded
    Sequoiadb该如何选择合适的SQL引擎
    scala的object知识点
    scala中同步块
    英语口语练习系列-C36-城市-谈论活动-登高
    英语口语练习系列-C35-马戏-谈论语言-己亥杂诗
    英语口语练习系列-C34-儿童-谈论物品和人-武陵春
    英语口语练习系列-C33-露营-谈论日期-离思
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5236847.html
Copyright © 2011-2022 走看看