zoukankan      html  css  js  c++  java
  • CodeForces 1420E Battle Lemmings

    题意

    略。

    ( exttt{Data Range:}1leq nleq 80)

    题解

    首先考虑初始状态怎么算答案。很明显直接数满足的不好数,用总的减去不满足的还比较好做。注意到所有不满足的是一段 (0),所以就没了。

    然后考虑怎么算从一个初始状态转移到一个目标状态的步数。考虑邻项交换,发现肯定是贪心匹配最优。

    所以说如果有一个目标序列的话那么就可以算出初始序列到这个序列的步数和这个序列的答案,于是就可以直接 DP 目标序列。(这个时候我们 DP 未被保护的对数的最小值)

    (f_{i,j,k}) 表示当前考虑到第 (i) 位并且钦定这一位填 (1),移动了 (j) 次并且这一段前缀中有 (k)(1) 时未被保护对数的最小值。实际上转移的话考虑枚举下一个 (1) 在哪里,这个时候可以算出中间一段 (0) 对答案的贡献和需要移动的步数,就能够转移了。

    最后处理的时候枚举一下最终序列中最后一个 (1) 填的哪里就好了,时间复杂度 (O(n^5))。由于我比较菜所以不会斜率优化做法。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=85;
    ll n,tot,res,m,r,c;
    ll x[MAXN],cnt[2],pos[MAXN],f[MAXN][MAXN*MAXN][MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline void chkmin(ll &x,ll y)
    {
        x=x<y?x:y;
    }
    inline ll binom(ll n)
    {
        return n*(n-1)/2;
    }
    int main()
    {
        m=binom(n=read());
        for(register int i=1;i<=n;i++)
        {
            cnt[x[i]=read()]++;
            x[i]?pos[cnt[1]]=i:1;
        }
        if(!cnt[0])
        {
            for(register int i=0;i<=m;i++)
            {
                printf("%d ",0);
            }
            return 0;
        }
        res=tot=binom(cnt[0]),memset(f,0x3f,sizeof(f));
        for(register int i=1;i<=n;i++)
        {
            f[i][abs(pos[1]-i)][1]=binom(i-1);
            for(register int j=0;j<=m;j++)
            {
                for(register int k=1;k<=i&&k<cnt[1];k++)
                {
                    r=cnt[1]-k;
                    if(f[i][j][k]!=0x3f3f3f3f)
                    {
                        for(register int l=i+1;l<=n-r+1;l++)
                        {
                            c=j+abs(pos[k+1]-l);
                            if(c<=m)
                            {
                                chkmin(f[l][c][k+1],f[i][j][k]+binom(l-i-1));
                            }
                        }
                    }
                }
            }
        }
        for(register int j=0;j<=binom(n);j++)
        {
            for(register int i=cnt[1];i<=n;i++)
            {
                if(f[i][j][cnt[1]]!=0x3f3f3f3f)
                {
                    chkmin(res,f[i][j][cnt[1]]+binom(n-i));
                }
            }
            printf("%d ",tot-res);
        }
    }
    
  • 相关阅读:
    [转]几个开源的.net界面控件
    电脑上设置对眼睛友好的绿豆沙色
    [转] C# 绘制报表,使用Graphics.DrawString 方法
    Excel 绘制图表,如何显示横轴的数据范围
    [转] C#中绘制矢量图形
    Chapter 3 Protecting the Data(3):创建和使用数据库角色
    续x奇数倍(n+2*x)暴力算法是冠军的算法结合数量
    新秀学习SSH(十四)——Spring集装箱AOP其原理——动态代理
    中国是大数据的人工智能的发源地
    采用shell脚本统计代码的行数
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13766422.html
Copyright © 2011-2022 走看看