题目链接:Dividing a String
题意:给定一个2*n(n<=20)的字符串及每个位置的字符包含的权重,求将该字符串分成两个子序列S1、T1,要求S1=T1且abs(weight1-weight2)尽可能地小。
分析:将字符串分成前半段和后半段来处理,对于前半段字符串从左往右枚举每个字符属于子序列S1还是T1,属于S1的子序列设为A,属于T1的子序列设为B,设A的长度不大于B,那么仅当A是B的前缀时,才有可能使S1=T1,对于后半段从右往左枚举,要求B不大于A且B为A的前缀,那么设他们多出来的那部分为C和C‘,则C和C’顺序互逆时S1=T1。因此map存下字符串C和倒过来的C'(即C),排序处理一下即可。
处理字符串C时,引用STL的map最好时14258ms,而且同一份代码还T了,后来自己写一个hashmap,10842ms妥妥AC了。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <map> #define LL long long using namespace std; const int inf = 0x3f3f3f3f; const int SEED = 171; const LL MOD = 100000000000007ll; const int N = 1500000+7; int a[50],b[50]; vector<int>val[N]; char str[50]; int numa,numb,num,x[25],y[25]; int gethash(char str[]) { LL res=str[0]; int len=strlen(str); for(int i=1;i<len;i++) { res=(res*SEED+str[i]+MOD)%MOD; } return res%N; } struct HASHMAP { int head[N],next[N],id[N],key[N]; int tot; void init() { memset(key,-1,sizeof(key)); memset(id,0,sizeof(id)); memset(head,-1,sizeof(head)); tot=0; } int find(char str[]) { int u=gethash(str); for(int i=head[u];~i;i=head[i]) { if(key[i]==u)return id[i]; } return 0; } void insert(char str[],int x) { int u=gethash(str); key[tot]=u;id[tot]=x;next[tot]=head[u];head[u]=tot++; } }HASH; int solve(int a,int x) { int sz=val[a].size(); if(sz==0)return inf; int low=0,high=sz-1,mid,ans=-1; while(low<=high) { mid=(low+high)>>1; if(val[a][mid]>=x) { ans=mid; high=mid-1; } else low=mid+1; } if(ans==-1)return abs(x-val[a][sz-1]); else if(ans==0)return abs(x-val[a][0]); else return min(abs(x-val[a][ans]),abs(x-val[a][ans-1])); } int main() { int n; while(scanf("%d",&n),n) { scanf("%s",str); num=0;//mp.clear(); HASH.init(); for(int i=0;i<2*n;i++)scanf("%d",&a[i]),b[i]=str[i]-'a',num+=b[i]; if(num&1) { puts("-1");continue; } for(int i=0;i<1<<n;i++)val[i].clear(); int sz=1; for(int s=0;s<1<<n;s++) { int tmp=__builtin_popcount(s); if(tmp>n-tmp)continue; numa=numb=num=0; for(int j=0;j<n;j++) { if(s&(1<<j)) { x[numa++]=b[j]; num-=a[j]; } else { y[numb++]=b[j]; num+=a[j]; } } if(numa<=numb) { int flag=0; for(int k=0;k<numa;k++)if(x[k]!=y[k]) { flag=1;break; } if(flag)continue; int siz=0; for(int k=numa;k<numb;k++)str[siz++]='0'+y[k]; str[siz]=0; // if(!mp[str])mp[str]=sz++; int temp=HASH.find(str); if(!temp) { HASH.insert(str,sz); temp=sz++; } int suf=temp; val[suf].push_back(num); } } for(int i=0;i<sz;i++)sort(val[i].begin(),val[i].end()); int ans=inf; for(int s=0;s<1<<n;s++) { int tmp=__builtin_popcount(s); if(tmp>n-tmp)continue; numa=numb=num=0; for(int j=n-1;j>=0;j--) { if(s&(1<<j)) { x[numa++]=b[n+j]; num-=a[n+j]; } else { y[numb++]=b[n+j]; num+=a[n+j]; } } if(numa<=numb) { int flag=0; for(int k=0;k<numa;k++)if(x[k]!=y[k]) { flag=1;break; } if(flag)continue; int siz=0; for(int k=numb-1;k>=numa;k--)str[siz++]='0'+y[k]; str[siz]=0; // if(!mp[str])continue; int temp=HASH.find(str); if(!temp)continue; int suf=temp; ans=min(solve(suf,num),ans); } } if(ans==inf)puts("-1"); else printf("%d ",ans); } }