Description
给出一个正整数序列 a,长度为 n,cyb 不喜欢完美,他要删掉一些数(也可以不删,即删掉0个),但是他不会乱删,他希望删去以后,能将 a 分成 2 个集合,使得两个非空集合的数的和相同,现在他希望你能帮他算出删数的方案数。
Input
第一行 n 个正整数
以下有 n行,每行1个
正整数表示整数序列a
Output
一个整数表示答案
Sample Input
4
1 2 3 4
Sample Output
3
Hint
30%:n<=5
100%:n<=20
100%:a 中每个元素<=100000000
题解
涉及到了$hash$,状压,双向搜索
首先可以想出一个$3^N$的搜索.
枚举每个是不选还是在$A$集合,还是在$B$集合
这样显然通不过$20$的数据
那么我们发现这个搜索是独立的
如果在$A$集合,我们令其为$-1*a$
在$B$集合,令其为$1*a$
那么实际上我们在找一个方程有多少组解.
这样,我们先搜前面一半,将和用$hash$存起来
将选的情况,用一个$2$进制数也存入$hash$
这样可以通过全部数据
1 #include<map> 2 #include<cmath> 3 #include<ctime> 4 #include<queue> 5 #include<stack> 6 #include<vector> 7 #include<cstdio> 8 #include<string> 9 #include<cstdlib> 10 #include<cstring> 11 #include<iostream> 12 #include<algorithm> 13 #define LL long long 14 #define RE register 15 #define IL inline 16 using namespace std; 17 const int MOD=1e6+7; 18 19 int n,lim; 20 int a[25]; 21 int ans; 22 bool vis[(1<<21)+5]; 23 struct HASH 24 { 25 int to,next,st; 26 }edge[MOD+5]; 27 int path[MOD+5],top; 28 29 void find_hash(int a,int st) 30 { 31 int k=(a%MOD+MOD)%MOD; 32 for (RE int i=path[k];i;i=edge[i].next) if (edge[i].to==a) vis[edge[i].st+st]=1; 33 } 34 void push_hash(int a,int st) 35 { 36 int k=(a%MOD+MOD)%MOD; 37 edge[++top].to=a; 38 edge[top].st=st; 39 edge[top].next=path[k]; 40 path[k]=top; 41 } 42 43 void Dfs(int cen,int tol,int set) 44 { 45 if (cen>lim) 46 { 47 push_hash(tol,set); 48 return; 49 } 50 Dfs(cen+1,tol,set); 51 Dfs(cen+1,tol+a[cen],set+(1<<cen-1)); 52 Dfs(cen+1,tol-a[cen],set+(1<<cen-1)); 53 } 54 void Dfs2(int cen,int tol,int set) 55 { 56 if (cen<=lim) 57 { 58 find_hash(tol,set); 59 return; 60 } 61 Dfs2(cen-1,tol,set); 62 Dfs2(cen-1,tol+a[cen],set+(1<<cen-1)); 63 Dfs2(cen-1,tol-a[cen],set+(1<<cen-1)); 64 } 65 66 int main() 67 { 68 scanf("%d",&n);lim=n/2; 69 for (RE int i=1;i<=n;i++) scanf("%d",&a[i]); 70 Dfs(1,0,0); 71 Dfs2(n,0,0); 72 for (RE int i=1;i<(1<<n);i++) ans+=vis[i]; 73 printf("%d",ans); 74 return 0; 75 }