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;
}
posted @   qscqesze  阅读(540)  评论(0编辑  收藏  举报
编辑推荐:
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 基于DeepSeek R1 满血版大模型的个人知识库,回答都源自对你专属文件的深度学习。
· 在缓慢中沉淀,在挑战中重生!2024个人总结!
· 大人,时代变了! 赶快把自有业务的本地AI“模型”训练起来!
· Tinyfox 简易教程-1:Hello World!
历史上的今天:
2015-03-02 Codeforces Round #294 (Div. 2)D - A and B and Interesting Substrings 字符串
2015-03-02 Codeforces Round #294 (Div. 2)C - A and B and Team Training 水题
2015-03-02 Codeforces Round #294 (Div. 2)B - A and B and Compilation Errors 水题
2015-03-02 Codeforces Round #294 (Div. 2)A - A and B and Chess 水题
点击右上角即可分享
微信分享提示