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

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-06 09:50:42

BZOJ 3139 [Hnoi2013]比赛 记忆化搜索的相关文章

【BZOJ】3139: [Hnoi2013]比赛

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3139 可以发现,答案之和得分的序列有关,而且和序列中每个元素的顺序无关.考虑HASH所有的状态,记忆化搜索即可. (取模出问题+没有判断是否访问,即答案为0的状态有的可能已经访问过了)调了一个多小时. #include<iostream> #include<cstdio> #include<algorithm> #include<vector> #i

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

题目链接:BZOJ - 1055 题目分析 这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多. 都是将现在 Solve 的区间分成子区间,再求解子区间. 这道题 Solve(l, r, x) 求能否将 [l, r] 的区间还原成 x ,那么就将它分成两段,看是否能左段变成 p , 右段变成 q. (x 能变成 pq) 代码 #include <iostream> #include <cstdio> #include <cstdlib> #

[BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】

题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标范围 [x, xx], 纵坐标范围 [y, yy] 的矩阵切成 k 块的最小 sigma((Vi - Ave)^2) . 然后再递归将矩阵分得更小,直到 k 为 1 的时候直接返回相应的值. 代码 #include <iostream> #include <cstdlib> #incl

BZOJ 1079: [SCOI2008]着色方案 记忆化搜索

1079: [SCOI2008]着色方案 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1079 Description 有n个木块排成一行,从左到右依次编号为1~n.你有k种颜色的油漆,其中第i种颜色的油漆足够涂ci个木块.所有油漆刚好足够涂满所有木块,即c1+c2+...+ck=n.相邻两个木块涂相同色显得很难看,所以你希望统计任意两个相邻木块颜色不同的

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&amp;&amp;NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇 今天早上起床发现194了然后就各种刷--当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题--结果尼玛调了能有一个小时--我居然没看到编号最小这个限制0.0 首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减 于是我们记忆化搜索 首先用

BZOJ 3895 取石子 博弈论+记忆化搜索

题目大意:给定n堆石子,两人轮流操作,每个人可以合并两堆石子或拿走一个石子,不能操作者输,问是否先手必胜 直接想很难搞,我们不妨来考虑一个特殊情况 假设每堆石子的数量都>1 那么我们定义操作数b为当前石子总数+当前堆数-1 若b为奇数,则先手必胜,否则后手必胜 证明: 若当前只有一堆,则正确性显然 否则: 若b为奇数,那么先手只需进行一次合成操作,此时操作数会-1,且仍不存在大小为1的堆 因此只需要证明b为偶数时先手必败即可 若先手选择了合成操作,那么操作数-1且不存在大小为1的堆,状态回到了b

【BZOJ 1415】 1415: [Noi2005]聪聪和可可 (bfs+记忆化搜索+期望)

1415: [Noi2005]聪聪和可可 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1640  Solved: 962 Description Input 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路. 所有的路都是无向的,即

BZOJ 2656 ZJOI 2012 数列(sequence) 高精度+记忆化搜索

题目大意:定义个一序列,f[i] = f[i / 2] (i % 2 == 0);f[i] = f[i / 2] + f[i / 2 + 1] (i % 2 == 1);求这个数列的第m项(m <= 10 ^ 100) 思路:数据范围高精度没跑了.记得之前做过这个题的弱化版,似乎是没有高精度的记忆化搜索,这个题就是加个高精度. CODE: #include <map> #include <cstdio> #include <cstring> #include &l

BZOJ 2656 ZJOI2012 数列(sequence) 高精度+记忆化搜索

题目大意:给定一个数列的通项公式,求数列的某一项 高精度+记忆化搜索没说的 其实不用记忆化搜索的但是既然写完了就写完了吧 顺便学习了一下友元函数之类的东西- - #include <map> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; class Big_Int{ private: int nu