• HDU 6017 Girls Love 233 BestCoder Round #92 1003 dp/记忆化搜索


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6017

    题意:给你一串只有2和3的字符串,你有m/2次操作,每次操作只能交换相邻的两个字符,使得到的233(三个字符是依次相邻的)最多。

    题解:首先考虑什么交换是有效的,很显然要交换2和3才能产生贡献。其次怎么统计233的个数,只要相邻的两个2的距离大于等于3,会使答案加一。接下来我们用搜索的思想来考虑。当第i个2移动的末端位置为x时,我们考虑i+1个2的可移动范围。对于i+1个2的右端可以到min(串的末端,i+1的当前位置+剩下操作数)。考虑左端,如果i+1个2在第i个2的前面,那么也就是相当于第i个移动到i+1的后面,也就是说所有2的相对位置不用变,那么i+1左端就是min(第i个2当前位置+1,i+1的当前位置-操作数)。接下来就是枚举位置寻找答案。但是如果只是暴力搜的话,重复搜到的状态是很多的,那么我们就可以记忆化来搜。
    接下来考虑状态的定义。在搜索的过程我们可以发现,当处理完第i个2的时候,那么第i个2对第i+1个2影响的因素有:第i个2的位置、剩下的操作数。那么我们就可以定义dp(i,j,k),意思是当处理第i个2时,前面i-1个2的最后一个2的位置是j,剩下操作数为k的最优答案。
    这题还会卡常。所以不能每次memset。
    PS:dp还是摸不透,弱的不行。不过各位大神的思想真的是很奇妙,可能是我太弱了。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    typedef unsigned long long ull;
    const int N=105;
    
    int T;
    int n,m,kase;
    char s[105];
    
    int dp[N][N][N],vis[N][N][N],p[N],c;
    
    int dfs(int id,int x,int w)
    {
    	if(id > c ) return n - x >= 2;
    	int& ans = dp[id][x][w];
    	if(vis[id][x][w] == kase ) return ans;
    	vis[id][x][w] = kase;
    	ans = -1e9;
    	int r = min(n,p[id] + w );
    	for(int i = max(x + 1, p[id] - w); i <= r; i++ )
    	{
    		int cost = abs(i - p[id]);
    		ans = max( ans , dfs( id + 1,i,w - cost) + (i - x > 2) * (id > 1));
    	}
    	return ans;
    }
    
    int main()
    {
    	cin>>T;
    	kase = 1;
    	memset(vis,0,sizeof(vis));
    	while(T--)
    	{
    		scanf("%d%d%s",&n,&m,s + 1);
    		m /= 2;
    		c = 0;
    		for(int i = 1 ;i <= n ;i++) if(s[i] == '2') p[++c] = i;
    		int ans = c == 0? 0 : dfs(1,0,m);
    		kase++;
    		printf("%d
    ",ans);
    	}
        return 0;
    }
    
    
  • 相关阅读:
    php2
    11-14php
    三层嵌套
    常见的浏览器兼容
    css中的一些问题及解决方法
    css
    html
    测试题
    正则表达式
    Math对象
  • 原文地址:https://www.cnblogs.com/zhuyutian/p/6444182.html
Copyright © 2020-2023  润新知