hdu4963 中途相遇

将序列分成两半,各n各字符。对于前一半,枚举每个字符属于T1还是T2,共2^n种情况。在一个方案中,T1的子序列为A,T2的子序列为B,我们假定A的长度不大于B的长度。显然,A是B的前缀才符合要求。令C=B-A,即B去掉A前缀后剩余的部分。同理,处理后一半得到一个C‘,就是去掉相同后缀后剩余的部分。当C=C'就是一个方案使得T1=T2。

主要有两点十分巧妙:1.枚举过程可以控制t1长度<=t2,这样能减少一半的枚举,但是会漏掉一些情况,比如第一个字符总是放在t2,实际也能放在t1,于是在len1==len2时另外交换两个串进行枚举。

2.如何快速匹配呢?我们记录的是两部分的权值之差,应该是取两部分w1-w2之和绝对值最小,可以变换为第一部分w1-w2和第二部分w2-w1之差绝对值最小,这样我们就记录第一部分的w1-w2,第二部分的w2-w1,现根据C排序,在根据权值之差排序,于是相邻的C和C'之差最小,可以O(n)解决。另外由于内存不够,把字符串C转化成数字,并记录长度,按长度排序再按C大小排序再按权值排序。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<set>
#define inf 1000000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=100005;
char s[50];
int d[50];
int n;
struct Node
{
    bool flag;
    int len;
    ll p;
    int w;
    bool operator<(const Node& u)const
    {
        if(len==u.len)
        {
            if(p==u.p)
                return w>u.w;
            return p<u.p;
        }
        return len<u.len;
    }
};
Node vec[2500000];
int num;
char t1[50],t2[50];
int w1,w2;
int len1,len2;
void dfs1(int u)
{
    if(u==n+1)
    {
        vec[num].flag=1;
        vec[num].len=len2-len1;
        vec[num].w=w1-w2;
        ll m=0;
        for(int i=len1;i<len2;i++)
        {
            if(t2[i]=='a')
                m=m*10+1;
            else
                m=m*10;
        }
        vec[num++].p=m;
        if(len1==len2)
        {
            vec[num].flag=1;
            vec[num].len=len2-len1;
            vec[num].w=w2-w1;
            vec[num++].p=m;
        }
        return;
    }
   if(len1<len2&&s[u]==t2[len1])
   {
        t1[len1++]=s[u];
        w1+=d[u];
        dfs1(u+1);
        len1--;
        w1-=d[u];
    }

    t2[len2++]=s[u];
    w2+=d[u];
    dfs1(u+1);
    len2--;
    w2-=d[u];

    if(len1==len2)
    {
        t2[len2++]=s[u];
        swap(w1,w2);
        w2+=d[u];
        dfs1(u+1);
        len2--;
        w2-=d[u];
        swap(w1,w2);
    }
}
void dfs2(int u)
{
    if(u==2*n+1)
    {
        vec[num].flag=0;
        vec[num].len=len1-len2;
        ll m=0;
        for(int i=len1-1;i>=len2;i--)
        {
            if(t1[i]=='a')
                m=m*10+1;
            else
                m=m*10;
        }
        vec[num].p=m;
        vec[num++].w=w2-w1;
        if(len1==len2)
        {
            vec[num].flag=0;
            vec[num].len=len1-len2;
            vec[num].p=m;
            vec[num++].w=w1-w2;
        }
        return;
    }
    t1[len1++]=s[u];
    w1+=d[u];
    dfs2(u+1);
    len1--;
    w1-=d[u];

    if(len1==len2)
    {
        t1[len1++]=s[u];
        swap(w1,w2);
        w1+=d[u];
        dfs2(u+1);
        len1--;
        w1-=d[u];
        swap(w1,w2);
    }

    if(len2<len1&&s[u]==t1[len2])
    {
        t2[len2++]=s[u];
        w2+=d[u];
        dfs2(u+1);
        len2--;
        w2-=d[u];
    }
}
int main()
{
    int a,b;
    while(~scanf("%d",&n)&&n)
    {
        a=0;b=0;
        scanf("%s",s+1);
        for(int i=1;i<=2*n;i++)
        {
            if(s[i]=='a')
                a++;
            if(s[i]=='b')
                b++;
        }
        for(int i=1;i<=n*2;i++)
            scanf("%d",&d[i]);
        if((a&1)||(b&1))
        {
            printf("-1\n");
            continue;
        }
        for(int i=n+1,j=2*n;i<j;i++,j--)
        {
            swap(s[i],s[j]);
            swap(d[i],d[j]);
        }
        if(a%2!=0||b%2!=0)
        {
            printf("-1\n");
            continue;
        }
        w1=w2=0;
        num=0;
        len1=len2=0;
        dfs1(1);
        w1=w2=0;
        len1=len2=0;
        dfs2(n+1);
        sort(vec,vec+num);
        int ans=inf;
        int p=-1,q=-1;
        for(int i=0;i<num;i++)
        {
            if(vec[i].flag==1)
            {
                p=i;
                if(i-1>=0&&(vec[i].p!=vec[i-1].p||vec[i].len!=vec[i-1].len))
                    q=-1;
            }
            if(vec[i].flag==0)
            {
                q=i;
                if(i-1>=0&&(vec[i].p!=vec[i-1].p||vec[i].len!=vec[i-1].len))
                    p=-1;
            }
            if(p==-1||q==-1)
                continue;
            ans=min(ans,abs(vec[p].w-vec[q].w));
        }
        if(ans==inf)
            printf("-1\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值