bzoj5248(洛谷4363)(2018九省联考)一双木棋

题目:https://www.luogu.org/problemnew/show/P4363

一种考虑状态数的方法:有几个用了k个格子的列,就在第k个0的左边插入几个1;

  这也是求不降序列的个数的方法。本题中这样一看,一共有C(10,20)个状态。*m得出记忆化搜索的时间复杂度是18e6左右。

利用hash和map记忆化搜索。那个dg可以设成全局变量,每次复原一下,就不用专门解hash了。之所以还要记s是为了记忆化搜索作角标。

其实这个代码只能在bzoj上A,洛谷上会超时。不超时的方法似乎是轮廓线dp之类。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define ll long long
using namespace std;
const ll INF=2e8;
int n,m,tot,base,dg[15];
ll a[2][15][15];
map<ll,ll> dp;
map<ll,bool> vis;
ll pw(ll a,int ct)
{
    ll ret=1;
    while(ct)
    {
        if(ct&1)ret*=a;
        a*=a;ct>>=1;
    }
    return ret;
}
ll dfs(ll s,bool k)
{
    if(vis[s])return dp[s];
    vis[s]=1;ll ret=-INF;
//    ll ts=s;
//    int dg[15]={0};
//    for(int i=1;i<=m;i++)dg[i]=ts%base,ts/=base;
    if(dg[m]==n)return 0;
    for(int i=1;i<=m;i++)
        if((i==1&&dg[i]<n)||dg[i-1]>dg[i])
        {
            dg[i]++;
            ret=max(ret,a[k][dg[i]][i]-dfs(s+pw(base,i-1),!k));
            dg[i]--;
        }
    return dp[s]=ret;
}
int main()
{
    scanf("%d%d",&n,&m);base=n+1;
    for(int k=0;k<=1;k++)for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%lld",&a[k][i][j]);
    printf("%lld",dfs(0,0));
    return 0;
}

 

posted on 2018-06-10 18:50  Narh  阅读(188)  评论(0编辑  收藏  举报

导航