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;
    }
  • 相关阅读:
    StringGrid 实例3: 本例功能: 1、修改 TStringGrid的默认宽与高; 2、添加行; 3、确认当前单元并赋值.
    StringGrid 实例2:1、获取 StringGrid 的行数、列数; 2、给单元赋值.
    StringGrid 实例1:初始化StirngGrid的首行和首列
    stringgrid事件大全
    firemonkey中stringgrid属性大全
    DELPHI声明一个指针变量,什么时候需要分配内存,什么时候不需要分配内存?
    CoolTrayIcon4.0
    Delphi七个版本
    基础
    按钮打开链接,按钮click代码
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5236847.html
Copyright © 2011-2022 走看看