hdu 4963(中途相遇法)

 

题目链接: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\n",ans);
    }
}
View Code

 

 

posted on 2015-04-29 17:52  lienus  阅读(542)  评论(0编辑  收藏  举报

导航