Luogu3067 平衡的奶牛群 Meet in the middle
Posted itst
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3067 平衡的奶牛群 Meet in the middle相关的知识,希望对你有一定的参考价值。
题意:给出$N$个范围在$[1,10^8]$内的整数,问有多少种取数方案使得取出来的数能够分成两个和相等的集合。$N leq 20$
发现爆搜是$O(3^N)$的,所以考虑双向搜索。
先把前$3^frac{N}{2}$搜完,然后每一次搜出后$3^frac{N}{2}$的时候,枚举前面的$2^frac{N}{2}$,每一个对应一下看有没有和为$0$的方案即可。复杂度为$O(6^frac{N}{2})$,虽然不开O2过不去qwq
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 inline int read(){
5 int a = 0;
6 char c = getchar();
7 while(!isdigit(c))
8 c = getchar();
9 while(isdigit(c)){
10 a = (a << 3) + (a << 1) + (c ^ ‘0‘);
11 c = getchar();
12 }
13 return a;
14 }
15
16 struct HashTable{
17 #define MOD 103
18 struct node{
19 int num;
20 node* nxt;
21 }*begin[MOD] , *last[MOD];
22 void insert(int num){
23 int t = num % MOD;
24 if(t < 0)
25 t += MOD;
26 if(last[t] == NULL){
27 begin[t] = new node;
28 begin[t]->num = num;
29 begin[t]->nxt = NULL;
30 last[t] = begin[t];
31 }
32 else{
33 node* now = new node;
34 now->num = num;
35 now->nxt = NULL;
36 last[t]->nxt = now;
37 last[t] = now;
38 }
39 }
40
41 bool count(int num){
42 int t = num % MOD;
43 if(t < 0)
44 t += MOD;
45 for(node* i = begin[t] ; i != NULL ; i = i->nxt)
46 if(i->num == num)
47 return 1;
48 return 0;
49 }
50 }zt[1 << 10];
51 int M[21] , N , ans;
52 bool is[1 << 10][1 << 10];
53
54 void init(int now , int end , int cnt , int sum){
55 if(now > end){
56 zt[cnt].insert(sum);
57 return;
58 }
59 init(now + 1 , end , cnt , sum);
60 init(now + 1 , end , cnt | (1 << now) , sum + M[now]);
61 init(now + 1 , end , cnt | (1 << now) , sum - M[now]);
62 }
63
64 void getAns(int now , int end , int cnt , int sum){
65 if(now > end){
66 for(int i = 0 ; i < 1 << (N >> 1) ; i++)
67 if(!is[cnt][i] && (zt[i].count(sum) || zt[i].count(-sum))){
68 is[cnt][i] = 1;
69 ans++;
70 }
71 return;
72 }
73 getAns(now + 1 , end , cnt , sum);
74 getAns(now + 1 , end , cnt | (1 << now - (N >> 1)) , sum + M[now]);
75 getAns(now + 1 , end , cnt | (1 << now - (N >> 1)) , sum - M[now]);
76 }
77
78 int main(){
79 N = read();
80 for(int i = 0 ; i < N ; i++)
81 M[i] = read();
82 init(0 , (N >> 1) - 1 , 0 , 0);
83 getAns(N >> 1 , N - 1 , 0 , 0);
84 cout << ans - 1;
85 return 0;
86 }
再放一个复杂度似乎不对但是很快的方法
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 struct node{
5 int zt , sum;
6 }num1[60010] , num2[60010];
7 int N , cnt1 , cnt2 , M[21];
8 bool vis[2000010];
9
10 void dfs(node* num , int& cnt , int now , int end , int sum , int zt){
11 if(now > end){
12 num[++cnt].sum = sum;
13 num[cnt].zt = zt;
14 return;
15 }
16 dfs(num , cnt , now + 1 , end , sum , zt);
17 dfs(num , cnt , now + 1 , end , sum + M[now] , zt | (1 << now));
18 dfs(num , cnt , now + 1 , end , sum - M[now] , zt | (1 << now));
19 }
20
21 bool cmp(node a , node b){
22 return a.sum < b.sum;
23 }
24
25 bool operator == (node a , node b){
26 return a.zt == b.zt && a.sum == b.sum;
27 }
28
29 int main(){
30 cin >> N;
31 for(int i = 0 ; i < N ; i++)
32 cin >> M[i];
33 dfs(num1 , cnt1 , 0 , (N - 2) >> 1 , 0 , 0);
34 dfs(num2 , cnt2 , N >> 1 , N - 1 , 0 , 0);
35 sort(num1 + 1 , num1 + cnt1 + 1 , cmp);
36 sort(num2 + 1 , num2 + cnt2 + 1 , cmp);
37 cnt1 = unique(num1 + 1 , num1 + cnt1 + 1) - num1 - 1;
38 cnt2 = unique(num2 + 1 , num2 + cnt2 + 1) - num2 - 1;
39 int p1 = cnt2 , p2 = cnt2;
40 for(int i = 1 ; i <= cnt1 ; i++){
41 while(p1 && num1[i].sum + num2[p1].sum > 0)
42 p1--;
43 p2 = p1;
44 while(p2 && num1[i].sum + num2[p2].sum >= 0)
45 p2--;
46 while(++p2 <= p1)
47 vis[num1[i].zt | num2[p2].zt] = 1;
48 }
49 int ans = 0;
50 for(int i = 1 ; i < 1 << N ; i++)
51 ans += vis[i];
52 cout << ans;
53 return 0;
54 }
以上是关于Luogu3067 平衡的奶牛群 Meet in the middle的主要内容,如果未能解决你的问题,请参考以下文章
折半搜索+状态压缩P3067 [USACO12OPEN]平衡的奶牛群Balanced Cow S…