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);
    }
}

时间: 2024-10-10 23:51:35

hdu 4963(中途相遇法)的相关文章

HDU 5936 Difference 【中途相遇法】(2016年中国大学生程序设计竞赛(杭州))

Difference Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 62    Accepted Submission(s): 19 Problem Description Little Ruins is playing a number game, first he chooses two positive integers y an

uva 6757 Cup of Cowards(中途相遇法,貌似)

uva 6757 Cup of CowardsCup of Cowards (CoC) is a role playing game that has 5 di?erent characters (Mage, Tank, Fighter,Assassin and Marksman). A team consists of 5 players (one from each kind) and the goal is to kill amonster with L life points. The

uva1152 - 4 Values whose Sum is 0(枚举,中途相遇法)

用中途相遇法的思想来解题.分别枚举两边,和直接暴力枚举四个数组比可以降低时间复杂度.可是我不会写...看了紫书作者刘汝佳老师的代码,真是太美了!简单明了,就像看吕钦下的棋一样.我就模仿的写了一下: #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<map> #include<set>

POJ 1840 Eqs Hash + 中途相遇法

把等式分成两拨算用中途相遇法就好了. 不过要注意的是这里不能用map,会超时,要自己手写hash,我重载了[]操作符之后用起来和map差不多,很随意 #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <string> #include <qu

Codeforces Round #297 (Div. 2) E题. Anya and Cubes (中途相遇法)

题目地址:Anya and Cubes 比赛的时候居然没想起中途相遇法...这题也是属于想起来就很简单系列. 中途相遇法也叫折半搜索.就是处理前一半,把结果储存起来,再处理后一半,然后匹配前一半存储的结果. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib

【中途相遇法】【STL】BAPC2014 K Key to Knowledge

题目链接: http://codeforces.com/gym/100526 http://acm.hunnu.edu.cn/online/?action=problem&type=show&id=11674&courseid=0 题目大意: N个学生M道题(1<=N<=12,1<=M<=30),每道题只有正误两种选项(0 1),每个学生的答题情况和正确题数已知,求标准答案可能有多少种. 如果标准答案只有一种则输出标准答案,否则输出解的个数. 题目思路: [

J 中途相遇法,求和

---恢复内容开始--- J - 中途相遇法 Time Limit:9000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Description The SUM problem can be formulated as follows: given four lists A, B, C, D<tex2html_verbatim_mark> of integer values, compute

codeforces 525 E Anya and Cubes 中途相遇法

codeforces 525 E Anya and Cubes 中途相遇法 题意: 给出n个数a1,a2,...,an,要求从中选出一些数,可以把其中最多k个变成它自己的阶乘,然后选出的数求和,问最后和等于s的选法有多少种. 限制: 1 <= n <= 25; 0 <= k <= n; 1<= s <= 1e16; 1 <= ai <= 1e9 思路: 一般数据量20~30都会考虑中途相遇法,就是折半暴力. ps:用三进制暴力会比直接深搜多一个常数10,因为

Codeforces 31E TV Game 中途相遇法 状压dp

题目链接:点击打开链接 题意: 给定2*n长的数字. 把这个数字拆成2个长度为n的数字,且相对位置不变.使得拆后得到的2个数字的和最大. 输出一个方案. 显然是中途相遇法,先计算左半段,再计算右半段 分别状压左半段和右半段,注意左半段状压后要在末尾补上0. 代码估计哪里有小越界==,数组开大了一点才过..具体就不查了. #include<iostream> #include<stdio.h> #include<string.h> #include<string&g

UVA 1326 Jurassic Remains 中途相遇法

题目链接:点击打开链接 题意:给定n个字符串,选尽可能多的字符串使得每种字母出现的次数为偶数次 思路: 中途相遇法 import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedLi