• 佣兵战纪


    前言

    第一题签到之后就睡麻了,这题都没想出来,满脑子都是区间DP,没救了。

    题目

    ( m 128MB,1s.)

    无题目链接。

    题目大意:

    炉石传说最近出了一个新模式:佣兵战纪。

    虽然我一度觉得这个模式完全没有天梯有意思,没有技术含量,还要高额氪金,但是架不住高额的任务奖励,还是打了两轮,只能说暴雪开始摆烂了。

    在这个模式中,玩家控制的佣兵分为红绿蓝三种颜色,具有克制关系:红色克制绿色,绿色克制蓝色,蓝色克制红色,克制可以造成双倍伤害。

    现在有一个只有 RGY 三种字符的字符串,表示这些佣兵,为了让比赛更好看,你决定让相邻的佣兵不是相同的类型,你可以执行以下操作任意次数:

    • 选择两个相邻的佣兵,交换他们。

    询问达到目的的最少操作次数,如果不能达到目的,输出 -1

    (1le nle 400.)

    讲解

    先判断无解:其中一种佣兵个数超过 (lceil frac{n}{2} ceil)

    再挖掘性质:相同颜色的佣兵相对顺序不会改变。

    然后我们直接枚举最终状态即可。

    (dp_{i,j,k,0/1/2}) 表示三种颜色的个数,最后一个颜色是谁,直接 ( t dp) 转移即可。

    由于空间不够,我用了鸽巢原理卡空间,时间复杂度 (O(n^3))

    代码

    打出来就过,完全不用调试的代码
    //12252024832524
    #include <bits/stdc++.h>
    #define TT template<typename T>
    using namespace std;
    
    typedef long long LL;
    const int MAXN = 405;
    const int INF = 0x3f3f3f3f;
    int n;
    int dp[MAXN][134][134][3];
    int ID[256],cnt[3],pos[3][MAXN],tot[3];
    char a[MAXN];
    
    LL Read()
    {
    	LL x = 0,f = 1; char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    TT void Put1(T x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    void ckmin(int &x,int y){x = Min(x,y);}
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); scanf("%s",a+1);
    	for(int i = 1;i <= n;++ i)
    		if(a[i] == 'R') ++cnt[0];
    		else if(a[i] == 'G') ++cnt[1];
    		else if(a[i] == 'Y') ++cnt[2];
    	if(Max(Max(cnt[0],cnt[1]),cnt[2]) > (n+1)/2) {Put(-1,'
    ');return 0;}
    	if(cnt[0] > 133) ID['G'] = 0,ID['Y'] = 1,ID['R'] = 2;
    	else if(cnt[1] > 133) ID['R'] = 0,ID['Y'] = 1,ID['G'] = 2;
    	else ID['R'] = 0,ID['G'] = 1,ID['Y'] = 2;
    	for(int i = 1;i <= n;++ i) pos[ID[a[i]]][++tot[ID[a[i]]]] = i;
    	memset(dp,0x3f,sizeof(dp));
    	if(tot[0]) dp[1][1][0][0] = pos[0][1]-1;
    	if(tot[1]) dp[1][0][1][1] = pos[1][1]-1;
    	if(tot[2]) dp[1][0][0][2] = pos[2][1]-1;
    	for(int i = 1;i < n;++ i)
    		for(int j = 0;j <= i && j <= tot[0];++ j)
    			for(int k = 0;j+k <= i && k <= tot[1];++ k)
    			{
    				if(i-j-k > tot[2]) continue;
    				for(int y = 0;y < 3;++ y)
    					for(int l = 0;l < 3;++ l)
    					{
    						if(y == l) continue;
    						if(!l) 
    						{
    							if(j == tot[0]) continue;
    							ckmin(dp[i+1][j+1][k][l],dp[i][j][k][y]+Max(0,pos[0][j+1]-(i+1)));
    						}
    						else if(l == 1)
    						{
    							if(k == tot[1]) continue;
    							ckmin(dp[i+1][j][k+1][l],dp[i][j][k][y]+Max(0,pos[1][k+1]-(i+1)));
    						}
    						else 
    						{
    							if(i-j-k == tot[2]) continue;
    							ckmin(dp[i+1][j][k][l],dp[i][j][k][y]+Max(0,pos[2][i+1-j-k]-(i+1)));
    						}
    					}
    			}
    	int ans = INF;
    	for(int i = 0;i < 3;++ i) ans = Min(ans,dp[n][tot[0]][tot[1]][i]);
    	Put(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    webStorage和cookie相比存在的优势
    session、localStorage和cookie之间的区别
    了解常见的状态码
    什么情况下会碰到跨域问题?有哪些方法可以解决
    什么是跨域?跨域请求资源的方式有哪些?
    垃圾回收机制
    400,500错误
    Junit添加完maven依赖无法使用@Test
    Maven资源过滤问题处理
    javascript的一些注意点
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15416343.html
Copyright © 2020-2023  润新知