1006.Touhou Red Red Blue
贪心/DP
题目大意
你将依次收到 n n n 个物品,他们具有颜色红、绿或蓝,记为 R , G , B R,G,B R,G,B
你有一个大小为
2
2
2 的物品栏。每当你收到一个物品,你可以考虑将其放入物品栏或直接丢弃
物品栏是一个栈,这意味着如果你决定放入物品但物品栏是满的,你将丢弃更早放入的那个物品,并将手上的物品放入
下面是物品的得分和消除规则:
- 如果手上和物品栏中共 3 3 3 个物品颜色相同,则消除这 3 3 3 个物品,得到 1 1 1 分(这是唯一的得分方式),并在物品栏得到 1 1 1 个颜色由你决定的新物品
- 如果手上和物品栏中共 3 3 3 个物品颜色各不相同,则消除这 3 3 3 个物品,并在物品栏得到 2 2 2 个颜色由你决定的新物品
求对于给定的物品序列,可以得到的最高分是多少
解题思路
官方给出的做法是DP,但是考虑所有的状态转移略显繁琐,难以不重复、不遗漏
相比起来我还是更喜欢直接贪心的方法//
思路来源:实验室某优秀学长
考虑一种游戏策略前,先掌握游戏核心机制
首先,在贪心的思想下,物品栏的栈特性可以不考虑//因为如果需要被迫丢弃物品,大可以在拿到这个物品时就直接丢弃//
其次,注意到颜色任选的物品可以不立刻考虑,作为任意物品
即可
考虑消除过程中的特点:
- 规则
2
2
2 消除后得到
2
2
2 个
任意物品
,可以配合规则 1 1 1 ,直接和下一个物品(若有)合成得分 - 规则
1
1
1 消除后留下
1
1
1 个
任意物品
。这意味着如果有得分,最后一定会留下 1 1 1 个任意物品
借助上面两个特点,单独考虑第一次消除,后续消除借助前面得到的任意物品
,具体可以参考代码注释
计数直到满足条件消除,即视为取需要的物品,并直接丢弃无帮助的物品,重新计数即可
时间复杂度
O ( n ) O(n) O(n)
参考代码
参考代码为已AC代码主干,其中部分功能需读者自行实现
int RGB(char c){
switch (c)
{
case 'R':return 1;
case 'G':return 2;
default:return 3;
}return 0;
}
void solve()
{
string s;cin >> s;
ll n=s.length(),res=0;
int cur=0,cnt[4]={0};
FORLL(i,0,n-1){
cur=RGB(s[i]);cnt[cur]++;
if(res){//消除过,前面必定有一个自选
if(cnt[1]&&cnt[2]||cnt[1]&&cnt[3]||cnt[2]&&cnt[3]){
//已有两种不同颜色+自选:选不同颜色,消3得2
if(i+1==n) break;//没有下一个就结束
i++;res++;//再用2个自选和下一个出现的颜色消除
cnt[1]=cnt[2]=cnt[3]=0;
}else if(cnt[1]==2||cnt[2]==2||cnt[3]==2){
//已有两个相同颜色+自选:选相同颜色,消3得1
res++;cnt[1]=cnt[2]=cnt[3]=0;
}
}else{//还没有消除过
if(cnt[1]&&cnt[2]&&cnt[3]){//兼有三色:消3得2
if(i+1==n) break;
i++;res++;//再用2个自选和下一个出现的颜色消除
cnt[1]=cnt[2]=cnt[3]=0;
}else if(cnt[1]==3||cnt[2]==3||cnt[3]==3){//有三个同色:消3得1
res++;cnt[1]=cnt[2]=cnt[3]=0;
}
}
}cout << res << endl;
}