BZOJ 3139 [Hnoi2013]比赛 记忆化搜索

题意:链接略

方法:记忆化搜索

解析:

记忆化搜索,状态内部压缩起始点以及所有点目前剩下的未匹配的分值。

注意不可以用map,因为我们记忆化的目的其实是大部分消除冗余的等于0的方案。

所以就得上hash表….

用map坑死我了。

代码:

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 15
#define szy 30123
#define mod 1000000007
using namespace std;
typedef long long ll;
int a[N];
int n;
ll ans;
int head[80010],cnt;
struct node
{
    ll from,to,val;
    int next;
}edge[80010];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void edgeadd(ll from,ll to,ll val)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
ll find(ll x)
{
    int szyszy=x%szy;
    for(int i=head[szyszy];i!=-1;i=edge[i].next)
    {
        if(edge[i].to==x)return edge[i].val;
    }
    return -1;
}
ll ins(ll x,ll val)
{
    int szyszy=x%szy;
    edgeadd(szyszy,x,val);
}
ll get_hash(int tmp[])
{
    ll ret=0;
    for(int i=0;i<=n;i++)ret=ret*30+tmp[i];
    return ret;
}
void bac(int tmp[],ll x)
{
    for(int i=n;i>=0;i--)tmp[i]=x%30,x/=30;
}
ll dfs0(ll x);
ll dfs(int arr[],int nowx,int nowy)
{
    ll ans=0;
    if(nowy>n)
    {
        if(arr[nowx]==0)
        {
            int t[N];
            for(int i=1;i<=n;i++)t[i]=arr[i];
            sort(t+1,t+n+1);t[0]=nowx;
            return dfs0(get_hash(t));
        }else return 0;
    }
    arr[nowx]-=3;
    if(arr[nowx]>=0&&arr[nowy]>=0)ans+=dfs(arr,nowx,nowy+1);
    arr[nowx]+=3;
    arr[nowy]-=3;
    if(arr[nowx]>=0&&arr[nowy]>=0)ans+=dfs(arr,nowx,nowy+1);
    arr[nowy]+=3;
    arr[nowx]--,arr[nowy]--;
    if(arr[nowx]>=0&&arr[nowy]>=0)ans+=dfs(arr,nowx,nowy+1);
    arr[nowx]++,arr[nowy]++;
    return ans;
}
ll dfs0(ll x)
{
    int tmp=find(x);
    if(tmp!=-1)return tmp;
    int c[N];
    bac(c,x);
    if(c[0]==n&&c[n]==0)return 1;
    ll sum=dfs(c,c[0]+1,c[0]+2);
    ins(x,sum);
    return sum;
}
int main()
{
    init();
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    printf("%lld\n",dfs0(get_hash(a))%mod);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值