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.

Examples

Input
3 2
1 2 3
Output
2 3 4 5 6
Input
5 5
1 1 1 1 1
Output
5
Input
3 3
3 5 11
Output
9 11 13 15 17 19 21 25 27 33

题意:给定N个数a[],让你选择K个数,可以重复选,求其组合成的和有哪些。N、K、a[]<=1000;

思路:看成1000000项的多项式,如果存在a[]=x,则x的系数为1,然后多项式自乘K次,系数不为0的部分表示可以有K个数构成,可以用FFT+快速幂,为了避免精度误差,每次快速幂后把非0的改为1,免得变得很大后产生误差,复杂度O(1000000*log1000000*logK),有点大,稍微优化下常数可以卡过。

这里尝试 用NTT,由于系数可以达到1000^1000,所以需要除Mod,但是避免除一个Mod恰好变为0,所以我们取两个Mod避免hack。

快速幂+NTT   4398ms:

#include<bits/stdc++.h>
#define rep(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
#define MOD Mod
#define ll long long
const int G=;
const int maxn=;
int Mod;
int qpow(int v,int p)
{
int ans=;
for(;p;p>>=,v=1ll*v*v%Mod)
if(p&)ans=1ll*ans*v%Mod;
return ans;
}
void rader(int y[], int len) {
for(int i=,j=len/;i<len-;i++) {
if(i<j) swap(y[i],y[j]);
int k=len/;
while(j>=k) j-=k,k/=;
if(j<k) j+=k;
}
}
void NTT(int y[],int len,int opt) {
rader(y,len);
for(int h=;h<=len;h<<=) {
int wn=qpow(G,(MOD-)/h);
if(opt==-) wn=qpow(wn,Mod-);
for(int j=;j<len;j+=h) {
int w=;
for(int k=j;k<j+h/;k++) {
int u=y[k];
int t=(ll)w*y[k+h/]%MOD;
y[k]=(u+t)%MOD;
y[k+h/]=(u-t+MOD)%MOD;
w=(ll)w*wn%MOD;
}
}
}
if(opt==-) {
int t=qpow(len,MOD-);
for(int i=;i<len;i++) y[i]=(ll)y[i]*t%MOD;
}
}
void powNTT(int ans[],int a[],int x)
{
ans[]=;int len=;
while(x){
len<<=;
if(x&){
NTT(ans,len,); NTT(a,len,);
rep(i,,len-) ans[i]=(ll)ans[i]*a[i]%Mod;
NTT(ans,len,-); NTT(a,len,-);
}
NTT(a,len,);
rep(i,,len-) a[i]=(ll)a[i]*a[i]%Mod;
NTT(a,len,-);
x>>=;
}
}
int A[maxn],B[maxn],ans1[maxn],ans2[maxn];
int main()
{
int N,K,x;
scanf("%d%d",&N,&K);
rep(i,,N) scanf("%d",&x),A[x]=,B[x]=;
Mod=; powNTT(ans1,A,K);
Mod=; powNTT(ans2,B,K);
rep(i,,) if(ans1[i]||ans2[i]) printf("%d ",i);
return ;
}

洛谷给出的代码,https://www.luogu.org/problemnew/solution/CF632E ,只一次NTT,在DFT后把每个数单自求pow(K),就得到了正确答案。

(暂时不理解其解法的正确性,如果是正确的,其NTT的写法里可能也有玄机(因为把这个NTT板子套其他题,样例过不了),尚待解决。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
#define ll long long
const int G=;
const int maxn=;
int mod,n,k,rev[maxn],lim,ilim,s,wn[maxn+];
std::vector<int> v;
inline int pow(int x, int y) {
int ans=;
for(;y;y>>=,x=(ll)x*x%mod)
if(y&) ans=(ll)ans*x%mod;
return ans;
}
inline int& up(int& x, int y) { if ((x+=y)>=mod) x-=mod; return x; }
inline void NTT(int* A, int typ) {
rep(i,,lim-) if (i<rev[i]) swap(A[i], A[rev[i]]);
for (int i=;i<lim;i+=i) {
const int t=lim/i/;
for (int j=;j<lim;j+=i+i) {
for (int k=;k<i; k++) {
int w=typ?wn[t*k]:wn[lim-t*k];
int x=A[k+j],y=(ll)w*A[k+j+i]%mod;
up(A[k+j],y),up(A[k+j+i]=x,mod-y);
}
}
}
if (!typ) rep(i,,lim-) A[i]=(ll)ilim*A[i]%mod;
}
inline void init(int len,int tmod) {
mod=tmod; lim=; s=-;
while(lim<len) lim+=lim,s++; ilim=pow(lim,mod-);
rep(i,,lim-) rev[i]=rev[i>>]>>|(i&)<<s;
int w=pow(G,(mod-)/len);
wn[]=;
rep(i,,lim) wn[i]=(ll)(wn[i-])*w%mod;
}
int A[maxn], B[maxn];
int main() {
scanf("%d%d",&n,&k);
int x; rep(i,,n) scanf("%d",&x), A[x]=B[x]=;
init(, );
NTT(A, );
rep(i,,lim-) A[i]=pow(A[i],k);
NTT(A, );
rep(i,,) if (A[i]) v.push_back(i);
init(, );
NTT(B, );
for (int i = ; i < lim; i++) B[i] = pow(B[i], k);
NTT(B, );
rep(i,,) if (B[i]) v.push_back(i);
sort(v.begin(), v.end()); int tot=unique(v.begin(), v.end())-v.begin();
v.resize(tot);
for (int i : v) printf("%d ",i);
return ;
}

CF632E: Thief in a Shop(快速幂+NTT)(存疑)的更多相关文章

  1. CF1096. G. Lucky Tickets(快速幂NTT)

    All bus tickets in Berland have their numbers. A number consists of n digits (n is even). Only k dec ...

  2. BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)

    3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...

  3. CF632E Thief in a Shop 和 CF958F3 Lightsabers (hard)

    Thief in a Shop n个物品每个价值ai,要求选k个,可以重复.问能取到哪几个价值? 1 ≤ n, k ≤ 1000,1 ≤ ai ≤ 1000 题解 将选一个物品能取到的价值的01生成函 ...

  4. [CF632E]Thief in a Shop

    题目大意:有一个小偷,拿$k$个东西,有$n$种产品,每种产品都有无限多个.对于每个第$i$ 种产品,它的价值是$A_i$.可能偷走的物品价值之和. 题解:对于所有的物品构造生成函数$F(x)=\su ...

  5. BZOJ 3992 DP+NTT+快速幂

    思路: 普通的DP很好想吧 f[i][j]+=f[i-1][j*s[k]]  前i个数  mod m=j 的个数 m是质数  模数是质数  这就很有趣了 那么我们就求出来原根  所有的数都取指数 搞出 ...

  6. Codeforces632E Thief in a Shop(NTT + 快速幂)

    题目 Source http://codeforces.com/contest/632/problem/E Description A thief made his way to a shop. As ...

  7. 2018.12.31 bzoj3992: [SDOI2015]序列统计(生成函数+ntt+快速幂)

    传送门 生成函数简单题. 题意:给出一个集合A={a1,a2,...as}A=\{a_1,a_2,...a_s\}A={a1​,a2​,...as​},所有数都在[0,m−1][0,m-1][0,m− ...

  8. bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...

  9. 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂

    [BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...

随机推荐

  1. html 5中的新特性之强化表单元素及属性

    之前我们判断用户提交的是否是Email 的时候,往往使用js 进行判断,但在html5中可以有新的方式进行判断而且更简单 <!DOCTYPE html> <html lang=&qu ...

  2. 运维必备技能 WEB 日志分析

    文章节选自<Netkiller Monitoring 手札> 20.2. Web 20.2.1. Apache Log 1.查看当天有多少个IP访问: awk '{print $1}' l ...

  3. 20145229吴姗姗web安全基础实践

    20145229吴姗姗web安全基础实践 基础与实践 基础问题 (1)SQL注入攻击原理,如何防御 SQL注入就是把SQL语句插入到之前已经定义好的语句中,作为网页中的比如用户名输入来达到攻击的目的, ...

  4. 《Python学习手册》(三)

    string 字符串,和列表.元组,都适用序列操作. 关于python转义字符 迭代 for x in S: print(x) [c * 2 for c in S] Comparasion: > ...

  5. 自定义QSS

    /*QComboBox*/ QComboBox {border: 1px solid rgb(111, 156, 207);border-radius: 3px;padding: 1px 18px 1 ...

  6. Linux下的sed命令使用详解

    sed是stream editor的简称,也就是流编辑器.它一次处理一行内容,处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”pattern space,接着用sed命令处理缓冲区中的内容, ...

  7. Linux系统故障-Repair filesystem

    fsck /dev/hddn (代表根目录所在的区) fsck -A -y 重启系统可以进去了:- ) fsck命令的主要选项如下: -A 检查所有列在etc/fstab文件中的文件系统.带有这个选项 ...

  8. JavaEE之注解

    1注解:Annotation注解,是一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次,给计算机,JVM提供解读信息的. 2注解的作用:编译检查:代码分析,编 ...

  9. 给定字符串数组,用map的key保存数组中字符串元素,value保存字符串元素出现次数,最后统计个字符串元素出现次数

    import java.util.HashMap; public class map1 { public static void main(String[] args) { String[] arra ...

  10. XML 存储文档

    package com.kpsh.myself; import java.io.File;import java.io.FileWriter; import org.dom4j.Document;im ...