CF286E. Ladies' Shop
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:
- 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.
- 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.
- 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.
The first line contains space-separated integers n and m (1 ≤ n, m ≤ 106). The second line contains n distinct space-separated integers a1, a2, ..., an (1 ≤ a1 < a2 < ... < an ≤ m) — the bags' weight limits.
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 k space-separated integers p1, p2, ..., pk (1 ≤ p1 < p2 < ... < pk). If there are multiple solutions, print any of them.
6 10
5 6 7 8 9 10
YES
5
5 6 7 8 9
1 10
1
NO
1 10
6
YES
1
6
注意到:所有选出来的重量一定是给出来的bag的容量的子集;对于任意一个未被选的bag一定可以被表示成两个bag的容量和。
所以\(O(m^2)\)的做法就是枚举出所有二元组,并从答案集合中去掉二元组的和。然后利用多项式乘积某位置的指数等于其两个因子的指数之和这一性质,可以用FFT加速。\(O(m\log m)\)。
upd:4:1 太能扯了。。
题意是说有序列a,求一个元素数最少的序列b,满足1)a中每个元素都能被b的一个可重子集和表示 2)b中任意一个大小不超过m的可重子集和都在a中。
显然b的每个元素都在a中,考虑a有序,a中最小的元素肯定是b中最小元素,第二个元素显然只能有一个元素表示,考虑第三个元素,它可以是前两个元素的和,也可以是一个新元素,但处于b内元素数最少的考虑,我们倾向于前者。考虑一个贪心的过程,当前i个元素都被表示出来,若第i+1个无法被前面元素和表示,就加到b中。这一过程可以使用fft实现,构造一个关于a为指数的多项式自乘后观察$x^{a_{i+1}}$次项的系数是否为0即可,无解当表示出了奇怪的东西。
#include <algorithm> #include <cstdio> #include <cmath> #include <cstring> using std::swap; const int maxn = 1e6 + 1000; struct Complex { double Real, Imag; Complex(double Real = 0.0, double Imag = 0.0):Real(Real), Imag(Imag) { } Complex operator + (const Complex&rhs) { return Complex(Real + rhs.Real, Imag + rhs.Imag); } Complex operator - (const Complex&rhs) { return Complex(Real - rhs.Real, Imag - rhs.Imag); // notice ... -打错成+ ... } Complex operator * (const Complex&rhs) { return Complex(Real * rhs.Real - Imag * rhs.Imag, Real * rhs.Imag + rhs.Real * Imag); } }; void DFT(Complex*a, int N, int flag) { for(int i = (N >> 1), j = 1, k; j < N; i ^= k, ++j) { if(i < j) swap(a[i], a[j]); for(k = (N >> 1); i & k; i ^= k, k >>= 1); } for(int n = 2; n <= N; n <<= 1) { Complex Wn = Complex(cos(flag * 2 * M_PI / n), sin(flag * 2 * M_PI / n)); for(int i = 0; i < N; i += n) { Complex W = Complex(1, 0); for(int j = i; j < i + (n >> 1); ++j, W = W * Wn) { Complex u = a[j], v = W * a[j + (n >> 1)]; a[j] = u + v; a[j + (n >> 1)] = u - v; } } } if(flag == -1) { for(int i = 0; i < N; ++i) a[i].Real /= N; } } bool show[maxn]; int p[maxn], k, n, m, N; Complex a[maxn * 4]; int main() { scanf("%d%d", &n, &m); for(N = 1; N <= (m << 1); N <<= 1); for(int i = 1, x; i <= n; ++i) { scanf("%d", &x); show[x] = true; a[x] = Complex(1, 0); } DFT(a, N, 1); for(int i = 0; i < N; ++i) a[i] = a[i] * a[i]; DFT(a, N, -1); for(int i = 1; i <= m; ++i) { if(a[i].Real < 1e-5 && show[i]) { p[++k] = i; } else if(a[i].Real > 1e-5 && !show[i]) { puts("NO"); return 0; } } puts("YES"); printf("%d\n", k); for(int i = 1; i < k; ++i) { printf("%d ", p[i]); } printf("%d\n", p[k]); return 0; }