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
原文地址:https://www.cnblogs.com/bin-gege/p/6445974.html