CF632E: Thief in a Shop(快速幂+NTT)(存疑)

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 21 2 3

Output

2 3 4 5 6

Input

5 51 1 1 1 1

Output

5

Input

3 33 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=3;
const int maxn=5685760;
int Mod;
int qpow(int v,int p)
{
    int ans=1;
    for(;p;p>>=1,v=1ll*v*v%Mod)
      if(p&1)ans=1ll*ans*v%Mod;
    return ans;
}
void rader(int y[], int len) {
    for(int i=1,j=len/2;i<len-1;i++) {
        if(i<j) swap(y[i],y[j]);
        int k=len/2;
        while(j>=k) j-=k,k/=2;
        if(j<k) j+=k;
    }
}
void NTT(int y[],int len,int opt) {
    rader(y,len);
    for(int h=2;h<=len;h<<=1) {
        int wn=qpow(G,(MOD-1)/h);
        if(opt==-1) wn=qpow(wn,Mod-2);
        for(int j=0;j<len;j+=h) {
            int w=1;
            for(int k=j;k<j+h/2;k++) {
                int u=y[k];
                int t=(ll)w*y[k+h/2]%MOD;
                y[k]=(u+t)%MOD;
                y[k+h/2]=(u-t+MOD)%MOD;
                w=(ll)w*wn%MOD;
            }
        }
    }
    if(opt==-1) {
        int t=qpow(len,MOD-2);
        for(int i=0;i<len;i++) y[i]=(ll)y[i]*t%MOD;
    }
}
void powNTT(int ans[],int a[],int x)
{
    ans[0]=1;int len=1024;
    while(x){
        len<<=1;
        if(x&1){
            NTT(ans,len,1); NTT(a,len,1);
            rep(i,0,len-1) ans[i]=(ll)ans[i]*a[i]%Mod;
            NTT(ans,len,-1); NTT(a,len,-1);
        }
        NTT(a,len,1);
        rep(i,0,len-1) a[i]=(ll)a[i]*a[i]%Mod;
        NTT(a,len,-1);
        x>>=1;
    }
}
int A[maxn],B[maxn],ans1[maxn],ans2[maxn];
int main()
{
    int N,K,x;
    scanf("%d%d",&N,&K);
    rep(i,1,N) scanf("%d",&x),A[x]=1,B[x]=1;
    Mod=998244353; powNTT(ans1,A,K);
    Mod=1004535809; powNTT(ans2,B,K);
    rep(i,1,1000000) if(ans1[i]||ans2[i]) printf("%d ",i);
    return 0;
}

洛谷给出的代码,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=3;
const int maxn=1048576;
int mod,n,k,rev[maxn],lim,ilim,s,wn[maxn+1];
std::vector<int> v;
inline int pow(int x, int y) {
    int ans=1;
    for(;y;y>>=1,x=(ll)x*x%mod)
      if(y&1) 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,0,lim-1) if (i<rev[i]) swap(A[i], A[rev[i]]);
    for (int i=1;i<lim;i+=i) {
        const int t=lim/i/2;
        for (int j=0;j<lim;j+=i+i) {
            for (int k=0;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,0,lim-1) A[i]=(ll)ilim*A[i]%mod;
}
inline void init(int len,int tmod) {
    mod=tmod; lim=1; s=-1;
    while(lim<len) lim+=lim,s++;  ilim=pow(lim,mod-2);
    rep(i,0,lim-1) rev[i]=rev[i>>1]>>1|(i&1)<<s;
    int w=pow(G,(mod-1)/len);
    wn[0]=1;
    rep(i,1,lim) wn[i]=(ll)(wn[i-1])*w%mod;
}
int A[maxn], B[maxn];
int main() {
    scanf("%d%d",&n,&k);
    int x; rep(i,1,n) scanf("%d",&x), A[x]=B[x]=1;
    init(1048576, 998244353);
    NTT(A, 1);
    rep(i,0,lim-1) A[i]=pow(A[i],k);
    NTT(A, 0);
    rep(i,1,1000000) if (A[i]) v.push_back(i);
    init(1048576, 1004535809);
    NTT(B, 1);
    for (int i = 0; i < lim; i++) B[i] = pow(B[i], k);
    NTT(B, 0);
    rep(i,1,1000000) 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 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/9876927.html

时间: 2025-01-09 01:42:59

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

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

3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个.小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi.另外,小C认为这个问题的答案可能很大,因

CF632E Thief in a Shop

题目链接:http://codeforces.com/contest/632/problem/E 题目大意: 从 \(n\) 个不同的数中取 \(k\) 个(可重复取)并加起来,问最多能得到多少种不同的和,从小到大输出所有的和. (\(1 \le n,k,a_i \le 1000\)) 知识点: DP 解题思路: 首先明确一点:对于 \(5s\) 的时限,\(O(1e9)\) 的复杂度是可以过的,因此我们可以来考虑 \(DP\). 具体的方法是:先把 \(a[]\) 数组从小到大排序,将 \(a

BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂

3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1155  Solved: 532[Submit][Status][Discuss] Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中

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

[BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个.小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi.另外,小C认为这个问题的答案可能

Educational Codeforces Round 9 E. Thief in a Shop NTT

E. Thief in a Shop 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

【codeforces 623E】dp+FFT+快速幂

题目大意:用$[1,2^k-1]$之间的证书构造一个长度为$n$的序列$a_i$,令$b_i=a_1\ or\ a_2\ or\ ...\ or a_i$,问使得b序列严格递增的方案数,答案对$10^9+7$取模. 数据范围,$n≤1^{18}$,$k≤30000$. 考虑用dp来解决这一题,我们用$f[i][j]$来表示前$i$个数中,使用了$j$个二进制位(注意!并不是前$j$个),那么答案显然为$\sum_{i=0}^{k} \binom{n}{i} \times f[n][i]$. 考虑

CF1106F Lunar New Year and a Recursive Sequence(矩阵快速幂+bsgs+exgcd)

题面 传送门 前置芝士 \(BSGS\) 什么?你不会\(BSGS\)?百度啊 原根 对于素数\(p\)和自然数\(a\),如果满足\(a^x\equiv 1\pmod{p}\)的最小的\(x\)为\(p-1\),那么\(a\)就是\(p\)的一个原根 离散对数 对于素数\(p\),以及\(p\)的一个原根\(g\),定义\(y\)为\(x\)的离散对数,当且仅当\(g^y\equiv x\pmod{p}\),记\(y\)为\(ind_g x\).不难发现原数和离散对数可以一一对应.也不难发现离

【知识总结】多项式全家桶(四)(快速幂和开根)

上一篇:[知识总结]多项式全家桶(三)(任意模数NTT) 推荐小恐龙的博客(参考资料):多项式开根 (本文中一切多项式运算默认在模 \(x_n\) 意义下进行) 一.快速幂 多项式快速幂?首先有一种很显然的方式是把整数快速幂里面的整数乘法替换成多项式乘法 NTT ,复杂度 \(O(n\log^2n)\) . 然而还有一种 \(O(n\log n)\) 的做法:要求 \(B=A^k\) ,相当于求 \(\log_A B=k\) ,用换底公式得 \(\log_A B=\frac{\ln B}{\ln

luoguP5219 无聊的水题 I 多项式快速幂

有一个幼儿园容斥:最大次数恰好为 $m=$  最大次数最多为 $m$ - 最大次数最多为 $m-1$. 然后来一个多项式快速幂就好了. code: #include <cmath> #include <cstring> #include <algorithm> #include <cstdio> #include <string> #define ll long long #define ull unsigned long long using