codeforces 286 E. Ladies' Shop (FFT)

E. Ladies' Shop
time limit per test
8 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

A ladies' shop has recently opened in the city of Ultima Thule. To get ready for the opening, the shop bought n bags. Each bag is characterised by the total weight ai of the items you can put there. The weird thing is, you cannot use these bags to put a set of items with the total weight strictly less than ai. However the weights of the items that will be sold in the shop haven't yet been defined. That's what you should determine right now.

Your task is to find the set of the items' weights p1, p2, ..., pk (1 ≤ p1 < p2 < ... < pk), such that:

  1. Any bag will be used. That is, for any i (1 ≤ i ≤ n) there will be such set of items that their total weight will equal ai. We assume that there is the infinite number of items of any weight. You can put multiple items of the same weight in one bag.
  2. For any set of items that have total weight less than or equal to m, there is a bag into which you can put this set. Similarly, a set of items can contain multiple items of the same weight.
  3. Of all sets of the items' weights that satisfy points 1 and 2, find the set with the minimum number of weights. In other words, value k should be as small as possible.

Find and print the required set.

Input

The first line contains space-separated integers n and m (1 ≤ n, m ≤ 106). The second line contains ndistinct space-separated integers a1, a2, ..., an (1 ≤ a1 < a2 < ... < an ≤ m) — the bags' weight limits.

Output

In the first line print "NO" (without the quotes) if there isn't set pi, that would meet the conditions.

Otherwise, in the first line print "YES" (without the quotes), in the second line print an integer k (showing how many numbers are in the suitable set with the minimum number of weights), in the third line print kspace-separated integers p1, p2, ..., pk (1 ≤ p1 < p2 < ... < pk). If there are multiple solutions, print any of them.

Examples
input
6 10
5 6 7 8 9 10
output
YES
5
5 6 7 8 9
input
1 10
1
output
NO
input
1 10
6
output
YES
1
6

 

——————————————————————————

然后来谈谈这道题了

题面是给n个篮子,要求制造不限制数目的商品,要求这些商品任意组合(可重复)的和在<m时总能找到一个容量等于和的篮子

有解输出YES,个数,商品的值,多组解要求输出篮子数最少,没有输出NO

首先按照题意来说我们随便组合这些商品,获得的值都有一个篮子来装

那么如果我们按每个篮子的值制造一种商品,每个篮子的值都可以由一个原商品,或两个原商品得到

为什么不是三个或以上,建设是三个组成这个篮子值A的话其中两个组成的商品会有一个篮子B来装,按照我们的条件,这个篮子值B的商品已经被制造出来了,所以假设不成立

也就是这样——

(栗子)

n=3 m=3

篮子:1 2 3

我们制造出的商品:1 2 3

我们发现1 1 1可以填满容量为3的篮子

但是1 1组合是2 ,我们已经制造出了2

可以是3=1+2,当然也有3=3

这个说明我们只要这样制造商品,每个商品和所有商品(包括自身)重新组合,就可以得到所有m以内商品和的种类 ——

(例子)

n=3 m=6(修改m)

篮子:1 2 3

我们制造出的商品:1 2 3

可搭配出

1+1=2 1+2=3 1+3=4

2+1=3 2+2=4 2+3=5

3+1=4 3+2=5 3+3=6

我们通过这些值可以判断,创造出的4 5 6无法装下,所以是NO

如果m=3

n=3 m=3

篮子:1 2 3

我们制造出的商品:1 2 3

可搭配出

1+1=2 1+2=3 1+3=4

2+1=3 2+2=4 2+3=5

3+1=4 3+2=5 3+3=6

我们发现2 3能被重新组合出来所以我们贪心地删除2 3 答案就是1

2用来构建3的,怎么被删除了呢

如果2被删除,说明2也可以被构建,故删除

所以根据xa*xb=xa+b

我们可以根据(xa1*xa2...xan)2来判断两两组合的所有解,满足卷积,所以FFT

【两个版本的FFT↓】

  1 #include <cmath>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #define siji(i,x,y) for(int i=(x);i<=(y);++i)
  6 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j)
  7 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i)
  8 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j)
  9 typedef long long ll;
 10 const double PI=3.14159265358979323;//似乎精度要大大大大大大大
 11 using namespace std;
 12 struct complex {
 13     double r,i;
 14     complex(double real=0.0,double image=0.0) {
 15         r=real;i=image;
 16     }
 17     complex operator + (const complex &a)const {
 18         return complex(r+a.r,i+a.i);
 19     }
 20     complex operator - (const complex &a)const {
 21         return complex(r-a.r,i-a.i);
 22     }
 23     complex operator * (const complex &a) const{
 24         return complex(r*a.r-i*a.i,r*a.i+i*a.r);
 25     }
 26 }num1[4000006],num2[4000006];
 27 void brc(complex *p,int l) {
 28     int j=l/2;
 29     for(int i=1;i<l-1;++i) {//l-1是因为如果最后减完k=0,j=0
 30         if(i<j) swap(p[i],p[j]);
 31         int k=l/2;
 32         while(j>=k) {
 33             j-=k;
 34             k>>=1;
 35         }
 36         if(j<k) j+=k;
 37     }
 38 }
 39 //迭代版
 40 void FFT(complex *p,int l,double flag) {
 41     brc(p,l);
 42     complex u,t;
 43     for(int h=2;h<=l;h<<=1) {
 44         complex wn(cos(flag*2*PI/h),sin(flag*2*PI/h));
 45         for(int k=0;k<l;k+=h){
 46             complex w(1,0);
 47             for(int j=k;j<k+h/2;++j) {
 48                 u=p[j];
 49                 t=w*p[j+h/2];
 50                 p[j]=u+t;
 51                 p[j+h/2]=u-t;
 52                 w=w*wn;
 53             }
 54         }
 55     }
 56 }
 57 //递归版
 58 /*complex tmp[505];
 59 void FFT(complex *p,int dep,int l,double flag) {
 60     if((1<<dep)==l) return;
 61     int step=1<<dep;
 62     FFT(p,dep+1,l,flag);
 63     FFT(p+step,dep+1,l,flag);
 64     int newlen=l>>dep,half=newlen>>1;
 65     complex wn(cos(2*flag*PI/newlen),sin(2*flag*PI/newlen));
 66     complex w(1,0);
 67     for(int i=0,s=0;i<half;++i,s+=(step<<1)) {
 68         complex a=p[s];
 69         complex b=w*p[s+step];
 70         tmp[i]=a+b;
 71         tmp[i+half]=a-b;
 72         w=w*wn;
 73     }
 74     for(int i=0;i<newlen;++i) {
 75         p[i<<dep]=tmp[i];
 76     }
 77 }//IDFT要除l*/
 78 bool ok;
 79 int a,b[1000005],ans[1000005],ac[1000005],cnt;
 80 int n,m;
 81 void solve() {
 82     scanf("%d%d",&n,&m);
 83     int l=1;
 84     memset(b,0,sizeof(b));
 85     siji(i,1,n) {
 86         scanf("%d",&a);
 87         b[a]=1;
 88     }
 89     while(l<2*m) {l=l<<1;}
 90     xiaosiji(i,0,m) {
 91         num1[i]=complex((double)b[i],0.0);
 92         
 93     }
 94     FFT(num1,l,1);
 95     xiaosiji(i,0,l) {
 96         num2[i]=num1[i];
 97     }
 98     xiaosiji(i,0,l) {
 99         num1[i]=num1[i]*num2[i];
100     }
101     FFT(num1,l,-1);
102     for(int z=0;z<l;++z) num1[z].r/=l;
103     ok=true;
104     siji(i,0,m) {
105         ans[i]=(int)(num1[i].r+0.5);
106     }
107     //为什么我这个sb写了个进位??????
108     //明明这不是大整数乘法啊QAQ
109     siji(i,1,m) {
110         if(ans[i]>0) {
111             if(b[i]==1) {b[i]=0;}
112             else if(b[i]==0) {ok=0;}
113         }
114     }
115     if(ok) {
116         puts("YES");
117         siji(i,1,m) {
118             if(b[i]>0) ac[++cnt]=i;
119         }
120         printf("%d\n",cnt);
121         siji(i,1,cnt) {
122             printf("%d%c",ac[i]," \n"[i==cnt]);
123         }
124     }
125     else{
126         puts("NO");
127     }
128 }
129 int main(int argc, char const *argv[])
130 {
131     //freopen("f1.in","r",stdin);
132     solve();
133     return 0;
134 }

 

posted @ 2017-01-20 20:33  sigongzi  阅读(384)  评论(0编辑  收藏  举报