CF 632E Thief in a Shop

Thief in a Shop

题目描述
传送门:http://codeforces.com/problemset/problem/632/E

题解

完全背包问题
直接dp的话状态太大了存不下

考虑一个简单得多的问题,如果次数限制改成<=k次,那直接写个bfs就好了
如果这些数字里有0那<=k和=k的答案就是一样的了。
把每个数字都减去最小的那个,这样就制造出了一个‘0’。
然后bfs跑一遍再全部加上minx*k输出就好了

另一种做法
考虑k=2
等价于把所有数字的存在性搞成01串然后跑个卷积
k=3,那就跑两遍卷积
所以把01串构出来跑k-1遍卷积就好了
这东西用快速幂优化一下变成log然后就能过了

代码

bfs版本

#include<bits/stdc++.h>
#define N 1005
#define M 1000005
using namespace std;
int n,k,minn,q[M],s[N],w[M];

void bfs()
{
  int l=1,r=1;
  for(int i=1;i<=n;i++)q[r++]=s[i],w[s[i]]=1;
  while(l<r)
  {
    int x=q[l++];
    if(w[x]>=k)continue;
    for(int i=1;i<=n;i++)
      if(!w[x+s[i]])
        q[r]=x+s[i],w[q[r]]=w[x]+1,r++;
  }
}

int main()
{
  scanf("%d%d",&n,&k);minn=1001;
  for(int i=1;i<=n;i++)
    scanf("%d",&s[i]),minn=min(minn,s[i]);
  for(int i=1;i<=n;i++)s[i]-=minn;
  bfs();
  for(int i=0;i<=1000*k;i++)
    if(w[i])printf("%d ",minn*k+i);
  return 0;
}

fft版本

#include<bits/stdc++.h>
#define N 2100000
#define Pi atan2(0,-1)
#define eps 1e-4
using namespace std;
int n,k,m,L,len,rev[N],a[N],ans[N],c[N];
struct comp{
  double r,i;
  comp operator+(const comp &x)
  const{return (comp){r+x.r,i+x.i};}
  comp operator-(const comp &x)
  const{return (comp){r-x.r,i-x.i};}
  comp operator*(const comp &x)
  const{return (comp){r*x.r-i*x.i,r*x.i+i*x.r};}
}A[N],B[N],t[N];

void DFT(comp *x,int n,int inv)
{
  for(int i=0;i<n;i++)t[rev[i]]=x[i];
  for(int i=0;i<n;i++)x[i]=t[i];
  for(int i=1,d=2;i<=L;i++,d<<=1)
  {
    comp w0=(comp){cos(2*Pi*inv/d),sin(2*Pi*inv/d)},w,u,v;
    for(int j=0,k;j<n;j+=d)
      for(k=j,w=(comp){1,0};k<j+(d>>1);k++,w=w*w0)
        u=x[k],v=x[k+(d>>1)]*w,x[k]=u+v,x[k+(d>>1)]=u-v;
  }
  if(inv==-1)for(int i=0;i<n;i++)x[i].r/=n;
}

void mul(int *c,int *a,int na,int *b,int nb)
{
  for(len=1,L=0;len<=max(na,nb)*2;len<<=1,L++);
  for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1)<<(L-1);

  for(int i=0;i<len;i++)A[i]=(comp){a[i],0};
  for(int i=0;i<len;i++)B[i]=(comp){b[i],0};

  DFT(A,len,1);DFT(B,len,1);
  for(int i=0;i<len;i++)A[i]=A[i]*B[i];
  DFT(A,len,-1);

  for(int i=0;i<len;i++)
  {
    if(A[i].r>eps)c[i]=1;
    else c[i]=0;
  }
}

void copy(int *a,int *b,int n)
{
  for(int i=0;i<=n;i++)a[i]=b[i];
}

void Pow(int b)
{
  int na=m,nb=m;b--;
  for(int i=0;i<=m;i++)ans[i]=a[i];
  while(b)
  {
    if(b&1)mul(c,ans,na,a,nb),na+=nb,copy(ans,c,na);  
    mul(c,a,nb,a,nb);nb<<=1;copy(a,c,nb);b>>=1;
  }
}

int main()
{
  int x;
  scanf("%d%d",&n,&k);
  for(int i=1;i<=n;i++)
    scanf("%d",&x),a[x]=1,m=max(m,x);
  Pow(k);
  for(int i=1;i<=m*k;i++)
    if(ans[i]==1)printf("%d ",i);
  printf("\n");
  return 0;
}

猜你喜欢

转载自blog.csdn.net/wcy_1122/article/details/79242257