删数方案数(regex)
[题目描述]
给出一个正整数序列 a,长度为 n,cyb 不喜欢完美,他要删掉一些数(也可以不删,即删掉0个),但是他不会乱删,他希望删去以后,能将 a 分成 2 个集合,使得两个非空集合的数的和相同,现在他希望你能帮他算出删数的方案数。
[输入文件]
第一行 n 个正整数
以下有 n行,每行1个
正整数表示整数序列a
[输出文件]
一个整数表示答案
[输入样例]
4
1 2 3 4
[输出样例]
3
[数据范围]
30%:n<=5
100%:n<=20
100%:a 中每个元素<=100000000
题解:
对于前半部分和后半部分dfs枚举
将前半部分得到的值包括状态存进hash(去重),在把后半部分的所有状态去重在hash中查找
本来是用的三进制数表示存进子集A,存进子集B,删去3种状态,后面发现没有必要
因为是“删数的方案”,也就是除删去的数,AB集合间如何分配并不关心,所以直接二进制就行
注意hash不能只存值,还要保存二进制数以判重,保存二进制数的数组不能太小也不能大
hash的大小70000够了,状态数组zt[70000][700]正好AC,500则90分,100则75分
博客里上传了数据,在管理里的文件
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Node 7 { 8 long long s; 9 int p; 10 }f[70001]; 11 int n,zt[70001][701],len,h[1200001]; 12 long long ans,has[70001],sp[70001],inf,a[21]; 13 bool cmp(Node a,Node b) 14 { 15 return (a.s<b.s||(a.s==b.s&&a.p<b.p)); 16 } 17 void push_hash(long long x,int i) 18 {int j; 19 long long p=(x+1000000000)%70000; 20 while (has[p]!=inf&&has[p]!=x) 21 { 22 p++; 23 if (p>70000) p=1; 24 } 25 if (has[p]==inf) 26 { 27 has[p]=x; 28 sp[p]=1; 29 zt[p][sp[p]]=i; 30 } 31 else if (has[p]==x) 32 { 33 for (j=1;j<=sp[p];j++) 34 if (i==zt[p][j]) return; 35 sp[p]++; 36 zt[p][sp[p]]=i; 37 } 38 } 39 void ask_hash(long long x,int i) 40 {int j; 41 long long p=(x+1000000000)%70000; 42 while (has[p]!=inf&&has[p]!=x) 43 { 44 p++; 45 if (p>70000) p=1; 46 } 47 if (has[p]==x) 48 { 49 for (j=1;j<=sp[p];j++) 50 h[zt[p][j]|i]=1; 51 } 52 } 53 void dfs1(int x,long long s,int p) 54 {int i; 55 if (x>n/2) push_hash(s,p); 56 else 57 for (i=-1;i<=1;i++) 58 dfs1(x+1,s+i*a[x],p|((i!=0)<<(x-1))); 59 } 60 void dfs2(int x,long long s,int p) 61 {int i; 62 if (x>n) f[++len]=(Node){s,p}; 63 else 64 for (i=-1;i<=1;i++) 65 dfs2(x+1,s+i*a[x],p|((i!=0)<<(x-1))); 66 } 67 int main() 68 {int i,j; 69 long long s; 70 freopen("regex.in","r",stdin); 71 freopen("regex.out","w",stdout); 72 cin>>n; 73 memset(has,-127,sizeof(has)); 74 inf=has[0]; 75 for (i=1;i<=n;i++) 76 scanf("%lld",&a[i]); 77 dfs1(1,0,0);dfs2(n/2+1,0,0); 78 sort(f+1,f+len+1,cmp); 79 for (i=1;i<len;i++) 80 if (f[i].s==f[i+1].s&&f[i].p==f[i+1].p) f[i].s=(1<<30); 81 sort(f+1,f+len+1,cmp); 82 while (f[len].s==(1<<30)) len--; 83 for (i=1;i<=len;i++) 84 ask_hash(-f[i].s,f[i].p); 85 for (i=1;i<=(1<<n)-1;i++) ans+=h[i]; 86 //cout<<h[i]<<endl; 87 cout<<ans; 88 }