P9574 「TAOI-2」Break Through the Barrier 题解

文章讲述了如何通过构建和优化有限状态机解决一道关于BTTB序列扩展的问题,初始版本的问题在于未能正确识别连续T序列的扩展,Release1.0提供了一个初步思路,Release2.0通过改进状态转移规则解决了问题。最终的算法复杂度为O(n)。
摘要由CSDN通过智能技术生成

P9574 「TAOI-2」Break Through the Barrier 题解

原题链接

本题是一道找规律题目。

基本的思路是:
如果出现序列BTTB...或者BTTBTBTB...TB,就可以通过连续的向右操作将这两种序列之后连续的T序列TTT...的开头延长一个T

例如:

[BTTB]TBTBTTTTTT...
=>
TB[BTTB]TBTTTTTT...
=>
TBTB[BTTB]TTTTTT...
=>
TBTBTBBTTTTTTT...

(中括号代表每一次操作选定的序列)

同时,如果在一串T序列...TTT的结尾出现上面序列的对称形式,即...TTTBTTB或者...TTTBT...BTBTBTTB就可以将前面T的序列向后扩展一个T。操作顺序与向前扩展序列的操作顺序正好相反。

思路是用一个有限状态机来维护上面的状态,识别出在连续的T串头部和尾部的拓展序列。

Release 1.0 : 初步的思路

初步构建的有限状态机的状态转移图:

B
EOF,out 0
T,tot 1
B
T
EOF,out 0
B,out 1
T
EOF,out 1
B
EOF,out 2
T
EOF,out 2
B
EOF,out 2
B,out 2
T,tot 3
T,tot 3
T, tot tot+1
B
EOF,out tot
T
EOF,out tot
B
B,out tot
T
EOF,out tot
B,out tot+1
T,tot 3,out max tot,2
EOF,out max tot,2
START
B
END
tot++
BT
BTT
BTTB
BTTBT..
..TB
..TBT
..TBTT

这个状态机共有十一个内部状态,其中START为初始状态,是所有状态机开始运行的状态,相应的,END是终结状态,状态机将在这里结束运行。状态机有一个内部变量tot,该变量被用于计算T串中T的数目并最终形成输出。在每一条路径上的第一个单词表示该路径的转移条件。转移条件一共有三种:接收到T,接收到B,接收到\n(图中为EOF)。一些路径在转移的同时会修改内部变量。tot x意味着将内部变量tot赋值为xout x是状态机的输出,out max x,y意味着输出xy中较大的值,最终的输出为状态机在运行过程中的所有输出的最大值。

issue:

很可惜,hack掉这个状态机很简单。

BTTBTTBTTTTT

该序列可以通过如下修改:

BTT[BTTB]TTTTT
=>
BTTTBBTTTTTT

得到六个T连续的序列,同时也是该样例的正解,但是我们构造的状态机会输出5,因为状态机仅仅会将第二个BTTB中间的T序列识别为连续的T,并不会将其识别为可以被修改的序列。当运行至状态..TBTT时,再输入一个T仅仅会使得状态机重新开始计算T的数量,而忽略了该连续的T串头部同样可以扩张的可能。

Release 2.0

重新考量状态..TBTT之后的构造。不难发现,如果状态机处于该状态并且tot == 3时,T串的前方应当有一串BTTB,此时T串头部可扩展。故该状态的转移应当由外部条件和内部变量共同决定。 解决方案是仍不调整该点所转移到的状态,但是当tot == 3时,将tot的值赋为4

同时,在所有转移到状态tot++的路径中,有且仅有从状态BTTBT..和从前端可扩展的状态...TBTT中转移过来的路径可以构造出BTTB,故设一个新的内部变量flag,在通过上述两条路径转入状态tot++时将flag设为1,自己转入自己的时候该变量的值不变,其他的转入路径则将该变量设为0。同时,如果状态处于..TBTT,当且仅当tot==3同时flag==1的时候可以将tot设为4并转入状态tot++

最终的状态转移图:

B
EOF,out 0
T,tot 1,flag 0
B
T
EOF,out 0
B,out 1
T
EOF,out 1
B
EOF,out 2
T
EOF,out 2
B
EOF,out 2
B,out 2
T,tot 3,flag 0
T,tot 3,flag 1
T, tot tot+1
B
EOF,out tot
T
EOF,out tot
B
B,out tot
T
EOF,out tot
B,out tot+1
T,if tot==3 && flag==1 -> tot 4 else tot 3 flag 0,out max tot,2
EOF,out max tot,2
START
B
END
tot++
BT
BTT
BTTB
BTTBT..
..TB
..TBT
..TBTT

请注意..TBTT返回tot++的节点,仅当tot==3并且flag==1的时候将tot修改为4,这意味着序列前方存在一串BTTB

Accepted代码:


#include "bits/stdc++.h"
#define int long long

// 定义有限状态机的状态节点
#define START 	0
#define B_ 		1
#define BT 		2
#define BTT 	3
#define BTTB 	4
#define BTTBT 	5
#define TOT 	6
#define TB 		7
#define TBT 	8
#define TBTT 	9
#define END 	10

using namespace std;

int max(int x, int y) { return x > y ? x : y; }

// 有限状态机的实现
class solve {
public:
  int now;
  int tot;
  int Max;
  int flag;

  solve() {
    this->now = START;
    this->tot = 0;
    this->Max = 0;
    this->flag = 0;
  }

  void out(int x) { this->Max = max(Max, x); }

  void fun(char ch) {
    if (now == START) {
      if (ch == 'B') {
        now = B_;
        return;
      } else if (ch == 'T') {
        flag = 0;
        now = TOT;
        tot = 1;
        return;
      } else {
        now = END;
        out(0);
        return;
      }
    } else if (now == B_) {
      if (ch == 'B') {
        now = B_;
        return;
      } else if (ch == 'T') {
        now = BT;
        return;
      } else {
        now = END;
        out(0);
        return;
      }
    } else if (now == BT) {
      if (ch == 'B') {
        out(1);
        now = B_;
        return;
      } else if (ch == 'T') {
        now = BTT;
        return;
      } else {
        now = END;
        out(1);
        return;
      }

    } else if (now == BTT) {
      if (ch == 'B') {
        now = BTTB;
        return;
      } else if (ch == 'T') {
        tot = 3;
        flag = 0;
        now = TOT;
        return;
      } else {
        now = END;
        out(2);
        return;
      }
    } else if (now == BTTB) {
      if (ch == 'B') {
        now = B_;
        out(2);
        return;
      } else if (ch == 'T') {
        now = BTTBT;
        return;
      } else {
        now = END;
        out(2);
        return;
      }
    } else if (now == BTTBT) {
      if (ch == 'B') {
        now = BTTB;
        return;
      } else if (ch == 'T') {
        flag = 1;
        tot = 3;
        now = TOT;
        return;
      } else {
        out(2);
        now = END;
        return;
      }
    } else if (now == TOT) {
      if (ch == 'B') {
        now = TB;
        return;
      } else if (ch == 'T') {
        now = TOT;
        tot++;
        return;
      } else {
        out(tot);
        now = END;
        return;
      }
    } else if (now == TB) {
      if (ch == 'B') {
        out(tot);
        now = B_;
        return;
      } else if (ch == 'T') {
        now = TBT;
        return;
      } else {
        out(tot);
        now = END;
        return;
      }
    } else if (now == TBT) {
      if (ch == 'B') {
        now = TB;
        return;
      } else if (ch == 'T') {
        now = TBTT;
        return;
      } else {
        out(tot);
        return;
      }
    } else if (now == TBTT) {
      if (ch == 'B') {
        out(tot + 1);
        tot = 0;
        now = BTTB;
        return;
      } else if (ch == 'T') {
        out(max(tot, 2));
        if (tot == 3 && flag == 1) {
          flag = 1;
          tot = 4;
        } else {
          flag = 0;
          tot = 3;
        }
        now = TOT;
        return;
      } else {
        out(max(tot, 2));
        tot = 0;
        now = END;
        return;
      }
    } else {
    }
  }
};

int read() {
  int x = 0, f = 1;
  int c = getchar();
  while (c > '9' || c < '0') {
    if (c == '-') {
      f = -1;
    }
    c = getchar();
  }
  while (c >= '0' && c <= '9') {
    x = x * 10 + c - '0';
    c = getchar();
  }
  return x * f;
}

signed main() {
  int _ = read();

  while (_--) {
    int n = read();
    char *chlist = new char[n + 1];
    for (int i = 0; i < n; i++) {
      scanf("%c", &(chlist[i]));
    }

    // 向字符串的结尾添加结束状态机的标识符
    chlist[n] = '\n';
    
    // 新建一个状态机
    solve *S = new solve;

    for (int i = 0; i <= n; i++) {
	  // 遍历整个字符串并转移状态机的状态。
	  // 当然,也可以一边读入一边遍历,这样会节省一些空间。
      S->fun(chlist[i]);
    }
    cout << S->Max << endl;
  }
  return 0;
}

算法复杂度: O ( n ) O(n) O(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值