• BZOJ 4420二重镇题解


    链接

    思路借鉴了这个博客

    我们可以想到状压dp

    用一个十进制数来表示状态,即第i位表示位置i处的物品等级

    用f[i][j][k]表示第i天,仓库的物品等级为j,状态为k时的最大收益

    但是状态数貌似很多,开不下,同时上面的式子好像不太好转移

    我们可以预处理出所有的合法状态,即无法消除的状态,然后在预处理出所有状态可能的转移,即枚举空位放那些等级的物品,用e[i][j][k]表示状态i,在第k个空位填等级为j的物品会转移到的状态编号,dis[i][j][k]表示这种转移所得到的收益,这样就方便转移了

    注意到我们还要考虑到仓库中的物品,即会有f[i][j][k]转移到f[i][0][s]的情况,所以我们枚举第二维的顺序应该是倒序枚举(即最后考虑f[i][0]的状态)

    细节有点多,注意不要写挂

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    
    using namespace std;
    
    const int mn = 8;
    const int maxn = 105;
    const int mx = 25005;//状态总数
    
    char s[maxn];
    int n,m,a[mn],b[mn],cnt,g[maxn];
    int sit[mn],id[700005];
    int e[mx][mn][mn],dis[mx][mn][mn],head[mx];
    
    int xiao(int *a,int pos,int &val)
    {
        val=0;
        while(a[pos])
        {
            int tmp=a[pos],l=pos,r=pos;
            while(a[l]==a[l-1] && l>1) l--;
            while(a[r]==a[r+1] && r<n) r++;
            if(l==r) break;
            val+=(r-l+1)*(1<<tmp);
            for(int i=l;i<=r;i++)
                a[i]=0;
            a[pos]=(tmp+1)%6;
        }
        int tmp=0;
        for(int i=1;i<=n;i++)
            tmp=tmp*10+a[i];
        if(!id[tmp]) id[tmp]=++cnt;
        return id[tmp];
    }
    
    void dfs(int x)
    {
        //printf("%d
    ",x);
        if(x>n)
        {
            int now = xiao(a,0,b[0]);
            for(int i=1;i<=n;i++)
            {
                if(!a[i])
                {
                    ++head[now];
                    for(int j=1;j<=5;j++)
                    {
                        for(int k=1;k<=n;k++)
                            b[k]=a[k];
                        b[i]=j;
                        e[now][j][head[now]] = xiao(b,i,dis[now][j][head[now]]);
                    }
                }
            }
            return ;
        }
        for(int i=0;i<=5;i++)
        {
            if(x==1 || !a[x-1] || !i || a[x-1]!=i)
            {
                a[x]=i;
                dfs(x+1);
            }
        }
    }
    int f[maxn][mn][mx];
    int dp()
    {
        memset(f,-1,sizeof(f));
        int ans=0;
        f[0][0][1]=0;
        for(int i=0;i<=m;i++)
            for(int k=5;k>=0;k--)
                for(int j=1;j<=cnt;j++)
                {
                    if(f[i][k][j]>=0)
                    {
                        if(i<m)
                        {
                            for(int s=1;s<=head[j];s++)
                                f[i+1][k][e[j][g[i+1]][s]]=max(f[i+1][k][e[j][g[i+1]][s]],f[i][k][j]+dis[j][g[i+1]][s]);
                        }
                        if(k)
                        {
                            for(int s=1;s<=head[j];s++)
                                f[i][0][e[j][k][s]]=max(f[i][0][e[j][k][s]],f[i][k][j]+dis[j][k][s]);
                        }
                        else  f[i+1][g[i+1]][j]=max(f[i+1][g[i+1]][j],f[i][k][j]);
                        ans=max(ans,f[i][k][j]);
                    }
                }
        return ans;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        for(int i=1;i<=m;i++)
            g[i]=s[i]-'0';
        dfs(1);
        printf("%d
    ",dp());
        return 0;
    }
  • 相关阅读:
    Python的网络编程[0] -> socket[1] -> socket 模块
    Python的网络编程[0] -> socket[0] -> socket 与 TCP / UDP
    Python的功能模块[4] -> pdb/ipdb -> 实现 Python 的单步调试
    Python的功能模块[3] -> binascii -> 编码转换
    Python的功能模块[2] -> abc -> 利用 abc 建立抽象基类
    Python的功能模块[1] -> struct -> struct 在网络编程中的使用
    Python的功能模块[0] -> wmi -> 获取 Windows 内部信息
    Python的程序结构[8] -> 装饰器/Decorator -> 装饰器浅析
    Python的程序结构[7] -> 生成器/Generator -> 生成器浅析
    Python的程序结构[6] -> 迭代器/Iterator -> 迭代器浅析
  • 原文地址:https://www.cnblogs.com/logeadd/p/9779085.html
Copyright © 2020-2023  润新知