P4799 [CEOI2015 Day2]世界冰球锦标赛

题目大意:有$n$个数,求任意选出若干个数,使其和不大于$m$的方案数。

暴力:每个数只有两种情况:选或者不选,然后再二进制判断计数。

优化:

将其分成两个集合$A$和$B$,其中$|A| = |B| = \dfrac{n}{2}$

$A$处理前$n$个数的方案个数并保留总和,$B$同理。

然后``two-pointers``。

时间复杂度大概是$O\left(2 ^ {\frac{n}{2}}\right)$,$n \le 40$可以过。
 
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 int n;
 4 long long m;
 5 long long a[100];
 6 long long A[1 << 20 + 2], B[1 << 20 + 2];
 7 int Acnt = 0, Bcnt = 0;
 8 long long ans = 0;
 9 
10 inline long long read(void)
11 {
12     long long s = 0;
13     int w = 1;
14     char ch = getchar();
15     while (!isdigit(ch))
16     {
17         if (ch == '-')
18             w = -1;
19         ch = getchar();
20     }
21     while (isdigit(ch))
22     {
23         s = s * 10 + ch - '0';
24         ch = getchar();
25     }
26     return s * w;
27 }
28 
29 void dfs(int now, int nn, long long sum)
30 {
31     if (sum > m)
32         return;
33     if (now > nn)
34     {
35         if (nn == n)
36             A[++Acnt] = sum;
37         else
38             B[++Bcnt] = sum;
39         return;
40     }
41     dfs(now + 1, nn, sum);
42     dfs(now + 1, nn, sum + a[now]);
43     return;
44 }
45 
46 int qfind(int R, int L)
47 {
48     int l = 0, r = L;
49     int ans = 0;
50     while (l <= r)
51     {
52         int mid = (l + r) >> 1;
53         if (A[mid] + B[R] <= m)
54         {
55             ans = mid;
56             l = mid + 1;
57         }
58         else
59             r = mid - 1;
60     }
61     return ans;
62 }
63 
64 int main(void)
65 {
66     n = read(), m = read();
67     for (int i = 1; i <= n; i++)
68     {
69         a[i] = read();
70     }
71     dfs(1, n / 2, 0);
72     dfs(n / 2 + 1, n, 0);
73     sort(A + 1, A + Acnt + 1);
74     sort(B + 1, B + Bcnt + 1);
75     int l = Acnt, r = 1;
76 
77     while (l >= 1 && r <= Bcnt)
78     {
79         l = qfind(r, l);
80         ans += l;
81         r++;
82     }
83     printf("%lld\n", ans);
84     return 0;
85 }

 

posted @ 2020-10-02 22:35  luyiming123  阅读(250)  评论(2编辑  收藏  举报