列表

详情


NC53189. 有趣的家庭菜园 3

描述

译自 JOI 2019 Final T3「たのしいたのしいたのしい家庭菜園 Growing Vegetable is Fun 3
家庭菜园专家JOI先生在他的家庭菜园中种植了一种叫Joy草的植物。在他的菜园里,有N个花盆自东向西摆放,编号分别为。每个花盆中有一株Joy草。
春天到了,JOI先生注意到Joy草如他期望地长出了各种颜色的叶子,但他也发现Joy草的生长速度没有他期望的那么快。他查阅了书籍,找到了草的以下特点:
  • Joy草有三种品种,分别会长出红色、绿色和黄色的叶子。
  • 如果两株同一颜色的Joy草紧密相邻,它们的生长速度就会减慢。
因此,JOI先生决定重新摆放花盆,使得没有两株相邻的Joy草颜色相同。
花盆非常沉重,因此JOI先生每次只能交换相邻的两个花盆。形式化的说,JOI先生每次操作可以选择一个,然后交换花盆i和花盆i+1。
请编写一个程序,计算最少的交换次数。

输入描述

从标准输入中读取数据。
第一行一个整数N。
接下来一行一个长度为N的字符串S,每个字符为R,G,Y中的一个,表示Joy草的颜色。

输出描述

输出数据到标准输出中。
输出一行一个整数,表示完成目标所需的最少操作次数。如果无解,输出-1。

示例1

输入:

5
RRGYY

输出:

2

说明:

一种合法的方案是:
第一步:交换第三个花盆和第四个花盆。
第二步:交换第二个花盆和第三个花盆。
在交换完成后,Joy草的颜色序列为RYRGY
可以证明JOI先生不能用少于2次交换完成目标,所以答案为2。

示例2

输入:

6
RRRRRG

输出:

-1

说明:

在这个样例中,无论如何操作,都不能使任意两株相邻 Joy 草颜色不同。

示例3

输入:

20
YYGYYYGGGGRGYYGRGRYG

输出:

8

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 157ms, 内存消耗: 4472K, 提交时间: 2019-10-29 22:31:00

// ===================================
//   author: M_sea
//   website: http://m-sea-blog.com/
// ===================================
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
using namespace std;

inline void chkmin(int& x, int y) {
    if (y < x)
        x = y;
}
inline int read() {
    int X = 0, w = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')
            w = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') X = X * 10 + c - '0', c = getchar();
    return X * w;
}

const int N = 400 + 10;
const int inf = 0x3f3f3f3f;

int n, a[N];
char s[N];
int cnt[N], pos[3][N], sum[3][N];
int dp[2][N][N][3];

inline int cost(int x, int y, int z, int k) {
    int p = x + y + z + 1;
    if (x > cnt[0] || y > cnt[1] || z > cnt[2])
        return inf;
    if (k == 0) {
        if (x + 1 > cnt[0])
            return inf;
        int q = pos[0][x + 1];
        return q - p + max(0, y - sum[1][q]) + max(0, z - sum[2][q]);
    }
    if (k == 1) {
        if (y + 1 > cnt[1])
            return inf;
        int q = pos[1][y + 1];
        return q - p + max(0, x - sum[0][q]) + max(0, z - sum[2][q]);
    }
    if (k == 2) {
        if (z + 1 > cnt[2])
            return inf;
        int q = pos[2][z + 1];
        return q - p + max(0, x - sum[0][q]) + max(0, y - sum[1][q]);
    }
}

int main() {
    n = read();
    scanf("%s", s + 1);
    if (n == 1) {
        puts("0");
        return 0;
    }
    for (re int i = 1; i <= n; ++i) {
        if (s[i] == 'R')
            a[i] = 0, pos[0][++cnt[0]] = i;
        if (s[i] == 'G')
            a[i] = 1, pos[1][++cnt[1]] = i;
        if (s[i] == 'Y')
            a[i] = 2, pos[2][++cnt[2]] = i;
        for (re int j = 0; j < 3; ++j) sum[j][i] = sum[j][i - 1] + (a[i] == j);
    }
    memset(dp, 0x3f, sizeof(dp));
    dp[1][0][0][0] = pos[0][1] - 1;
    dp[1][1][0][1] = pos[1][1] - 1;
    dp[1][0][1][2] = pos[2][1] - 1;
    for (re int i = 2; i <= n; ++i) {
        int now = i & 1, pre = now ^ 1;
        memset(dp[now], 0x3f, sizeof(dp[now]));
        for (re int j = 0; j <= min(i, (i + 1) >> 1); ++j)
            for (re int k = 0; k <= min(i - j, (i + 1) >> 1); ++k) {
                if (i - j - k) {
                    int w = cost(i - j - k - 1, j, k, 0);
                    chkmin(dp[now][j][k][0], dp[pre][j][k][1] + w);
                    chkmin(dp[now][j][k][0], dp[pre][j][k][2] + w);
                }
                if (j) {
                    int w = cost(i - j - k, j - 1, k, 1);
                    chkmin(dp[now][j][k][1], dp[pre][j - 1][k][0] + w);
                    chkmin(dp[now][j][k][1], dp[pre][j - 1][k][2] + w);
                }
                if (k) {
                    int w = cost(i - j - k, j, k - 1, 2);
                    chkmin(dp[now][j][k][2], dp[pre][j][k - 1][0] + w);
                    chkmin(dp[now][j][k][2], dp[pre][j][k - 1][1] + w);
                }
            }
    }
    int ans = inf;
    for (re int i = 0; i <= (n + 1) >> 1; ++i)
        for (re int j = 0; j <= min(n - i, (n + 1) >> 1); ++j)
            for (re int k = 0; k < 3; ++k) chkmin(ans, dp[n & 1][i][j][k]);
    printf("%d\n", ans == inf ? -1 : ans);
    return 0;
}

C++(clang++11) 解法, 执行用时: 56ms, 内存消耗: 4368K, 提交时间: 2020-11-20 19:33:17

#include<bits/stdc++.h>
using namespace std;

const int N=405;
char s[N];
int n,ans,cnt[3],g[N][3],pos[N][3],dp[2][N][N][3];
inline int id(char x){if(x=='R') return 0;if(x=='G') return 1;return 2;}
int main()
{
	scanf("%d %s",&n,s+1);
	for(int i=1;i<=n;++i){int x=id(s[i]);for(int j=0;j<=2;++j) g[i][j]=g[i-1][j];g[i][x]++;pos[++cnt[x]][x]=i;}
	memset(dp,0x3f,sizeof(dp));ans=dp[0][0][0][0];
	for(int i=0;i<=2;++i) dp[0][0][0][i]=0;
	for(int i=1,x=1,y=0;i<=n;++i,x^=1,y^=1)
	{
		memset(dp[x],0x3f,sizeof(dp[x]));
		for(int j=min(i,cnt[0]);j>=0;--j)
		for(int k=min(i-j,cnt[1]);k>=0;--k)
		{
			if(i-j-k>cnt[2]) break;
			if(j) dp[x][j][k][0]=min(dp[y][j-1][k][1],dp[y][j-1][k][2])+max(0,g[pos[j][0]][1]-k)+max(0,g[pos[j][0]][2]-(i-j-k));		
			if(k) dp[x][j][k][1]=min(dp[y][j][k-1][0],dp[y][j][k-1][2])+max(0,g[pos[k][1]][0]-j)+max(0,g[pos[k][1]][2]-(i-j-k));
			if(i-j-k) dp[x][j][k][2]=min(dp[y][j][k][0],dp[y][j][k][1])+max(0,g[pos[i-j-k][2]][0]-j)+max(0,g[pos[i-j-k][2]][1]-k);
		}
	}
	for(int i=0;i<=2;++i) ans=min(ans,dp[n&1][cnt[0]][cnt[1]][i]);
	printf("%d",ans!=dp[0][n][n][0]?ans:-1);
}

上一题