zoukankan      html  css  js  c++  java
  • hdu 6017 Girls Love 233(dp)

    题目链接:hdu 6017 Girls Love 233

    题意:

    给你一串含2,3的串,现在最多交换m/2次,问最多能形成多少个233

    题解:bc官方题解:

    大家要学会分析状态啊喂!多思考多开脑洞,分析出状态之后,就是一个DP或者记忆化搜索,自然就可以写出来啦!

    首先,因为字符不是'2'就是'3',所以我们可以把字符串当做一个全部都是'3'的串,然后有若干的'2'插入到了某些位置。

    显然,我们交换相邻的'2'与'2'或者相邻的'3'与'3'是没有意义的,我们只会进行相邻'2'与'3'之间的交换。因此,所有'2'的相对前后关系其实是不会变化的。

    做了这些比较基础的分析之后,基于数据规模很小,我们可以用以下4个要素表示完整的状态:

    1.处理到第几个'2'

    2.最后一个'2'停留在什么位置,如果当前的'2'与上一个'2'距离相差>=2时则对答案+1

    3.呃喵的剩余交换次数是多少

    4.当前已经成功得到几个"233"

    而这四个要素的大小,最坏情况下分别是n、n、m、n级别的数,我们随便以3个要素作为下标对应状态,使得第4个要素最优做DP. 转移的时候步长也是不超过2m的,所以很容易就可以得出复杂度为O(n * n * m/2 * m)的算法,这个对于本题的时限和数据,没有什么作死写法的话是可以完全无压力顺利AC的。

    这题本来是放在02的,可以用Big Zhu God式爆搜通过,但是后来被调整到03,也相应卡掉了大力爆搜。

    最后还要提下,claris老师提供了一个复杂度更加优秀的O(n * n * n * 3)的做法,大体如下——

    考虑最后形成的串是'2'与'3'归并排序后的结果。

    于是我们显然需要知道——

    1.当前选了多少个2

    2.当前选了多少个3

    3.当前用了多少次交换

    4.影响决策的状态,这里有3种情况——

    a.不存在前一个'2',或者前一个'2'后面已经有了足够的'3',记做状态0
    
    b.前一个'2'后面只有0个'3',记做状态1
    
    c.前一个'2'后面只有1个'3',记做状态2
    

    用g2与g3表示2与3个个数,用p[]记录所有2的位置,于是就可以有——

    for(i)for(j)for(k)for(t)if(~f[i][j][k][t])
    
    {
    
        if (i < g2)//我们可以考虑接下来放置一个'2'
    
        {
    
            int sum = k + abs(i + j + 1 - p[i + 1]);
    
            if (sum <= m)gmax(f[i + 1][j][sum][1], f[i][j][k][t]);
    
        }
    
        if (j < g3)//我们可以考虑接下来放置一个'3'
    
        {
    
            int sta = t; int cnt = f[i][j][k][t];
    
            if (sta)
    
            {
    
                if (sta < 2)++sta;
    
                else sta = 0, ++cnt;
    
            }
    
            gmax(f[i][j + 1][k][sta], cnt);
    
        }
    
    }最后在f[g2][g3][0~m][0~2]中更新答案。
    

    PS:由于数据组数过多,直接memset复杂度是1e6*1000级别,会导致TLE哦~ 其实初测已经给了很多组数,目的就是让memset的代码意识到其可能会FST.

     1 #include<bits/stdc++.h>
     2 #define F(i,a,b) for(int i=a;i<=b;++i)
     3 using namespace std;
     4 const int N=107;
     5 
     6 int t,n,m,dp[N][51][N],pos[N],cnt,J,ans,inf=1e9+7;
     7 char s[N];
     8 
     9 inline void up(int &a,int b){if(a<b)a=b;}
    10 
    11 int main()
    12 {
    13     scanf("%d",&t);
    14     while(t--)
    15     {
    16         scanf("%d%d",&n,&m),m/=2;
    17         scanf("%s",s+1);
    18         cnt=0;
    19         F(i,1,n)if(s[i]=='2')pos[++cnt]=i;
    20         F(i,0,cnt)F(j,0,m)F(k,0,n)dp[i][j][k]=-inf;
    21         F(i,1,n)if(abs(pos[1]-i)<=m)dp[1][abs(pos[1]-i)][i]=0;
    22         F(i,2,cnt)F(j,0,m)F(k,0,n)
    23         {
    24             if(dp[i-1][j][k]==-inf)continue;
    25             F(p,k+1,n)
    26             {
    27                 if((J=abs(pos[i]-p)+j)>m)continue;
    28                 if(p-k>=3)up(dp[i][J][p],dp[i-1][j][k]+1);
    29                 else up(dp[i][J][p],dp[i-1][j][k]);
    30             }
    31         }
    32         ans=0;
    33         F(j,0,m)F(k,0,n)up(ans,dp[cnt][j][k]+(n-k>=2));
    34         printf("%d
    ",ans);
    35     }
    36     return 0;
    37 }
    View Code
  • 相关阅读:
    string
    luogu1419 寻找段落
    vijos2024 无向图最短路径
    [Tjoi2016&Heoi2016]排序
    Vijos1083 小白逛公园
    [ZJOI2007]矩阵游戏
    NOIP2015 信息传递
    [HAOI2006]受欢迎的牛
    luogu3834 【模板】可持久化线段树 1(主席树)
    luogu2625 豪华游轮
  • 原文地址:https://www.cnblogs.com/bin-gege/p/6445974.html
Copyright © 2011-2022 走看看