CF 632E

Posted zhangleo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF 632E相关的知识,希望对你有一定的参考价值。

本题是一道好题...

首先我们可以看到,本题其实可以用完全背包跑,但是复杂度不对

所以我们考虑优化:

我们知道,如果有三个物品价值分别为技术图片

如果允许取一个物品,那么技术图片都是合法的答案

如果允许取三个物品,那么技术图片就是一个合法的价值(废话)

这是否给了我们一些启示呢?

如果我们设集合技术图片,构造一个多项式技术图片

可以发现,如果k=1,那么这个多项式中每个技术图片项前系数不为0的i即为合法答案

如果k=2,那么这个多项式自乘一次,每个技术图片项前系数不为0的即为合法答案

(这一点很好理解,一个技术图片项前系数不为0的条件是当且仅当至少存在一对j,k使得在原多项式中技术图片前系数均不为0,且技术图片,而根据定义,如果技术图片前系数不为0,说明技术图片,那么也就是选出了两件物品嘛)

因此,对于任意的k,我们只需要将构造出的多项式自乘k次,然后找出系数不为0的项,输出答案即可

接下来谈几个细节:

首先,本题数据范围过大,因此FFT是难以通过的,建议使用NTT

其次,NTT的常用模数会被卡(比如998244353和1004535809),因此需要用一些不常见的东西,比如469762049(原根为3),这个东西亲测不会卡(如果你非要用前两个,请使用双模)

然后就结束了

#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#define ll long long
using namespace std;
const double pi=acos(-1.0);
//const ll mode1=998244353;
const ll mode=469762049;
int to[(1<<21)+5];
int n,lim=1,l;
int m,k;
ll pow_mul(ll x,ll y)
{
    ll ans=1;
    while(y)
    {
        if(y&1)ans=ans*x%mode;
        x=x*x%mode,y>>=1;
    }
    return ans;
}
void NTT(ll *a,int len,int k)
{
    for(int i=0;i<len;i++)if(i<to[i])swap(a[i],a[to[i]]);
    for(int i=1;i<len;i<<=1)
    {
        ll w0=pow_mul(3,(mode-1)/(i<<1));
        for(int j=0;j<len;j+=(i<<1))
        {
            ll w=1;
            for(int o=0;o<i;o++,w=w*w0%mode)
            {
                ll w1=a[j+o],w2=a[j+o+i]*w%mode;
                a[j+o]=(w1+w2)%mode,a[j+o+i]=((w1-w2)%mode+mode)%mode;
            }
        }
    }
    if(k==-1)for(int i=1;i<(len>>1);i++)swap(a[i],a[len-i]);
}
ll a[(1<<21)+5],b[(1<<21)+5],c[(1<<21)+5];
ll temp[(1<<21)+5];
int n1,n2;
void pow_mul()
{
    b[0]=1;
    while(k)
    {
        if(k&1)
        {
            lim=1,l=0;
            while(lim<=2*max(n1,n2))lim<<=1,l++;
            for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1)));
            for(int i=0;i<lim;i++)temp[i]=a[i];
            NTT(b,lim,1),NTT(temp,lim,1);
            for(int i=0;i<lim;i++)c[i]=temp[i]*b[i]%mode;
            NTT(c,lim,-1);
            ll inv=pow_mul(lim,mode-2);
            for(int i=0;i<lim;i++)b[i]=c[i]*inv%mode,c[i]=temp[i]=0;
            n2+=n1;
        }
        lim=1,l=0;
        while(lim<=2*n1)lim<<=1,l++;
        for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1)));
        NTT(a,lim,1);
        for(int i=0;i<lim;i++)c[i]=a[i]*a[i]%mode;
        NTT(c,lim,-1);
        ll inv=pow_mul(lim,mode-2);
        for(int i=0;i<lim;i++)a[i]=c[i]*inv%mode,c[i]=0;
        k>>=1;
        n1<<=1;
    }
    for(int i=0;i<n2;i++)if(b[i]>0)printf("%d ",i);
    printf("\n");
}
int main()
{
    scanf("%d%d",&m,&k);
    n1=1000,n2=1000;
    for(int i=1;i<=m;i++)
    {
        int t;
        scanf("%d",&t);
        a[t]=1;
    }
    pow_mul();
    return 0;
}

 

以上是关于CF 632E的主要内容,如果未能解决你的问题,请参考以下文章

cf 632E FFT+快速幂

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

CF632E Thief in a Shop

CodeForces - 632E Thief in a Shop 完全背包

CodeForces 632E Thief in a Shop

CodeForces 632E Thief in a Shop